package com.ulife.order.components;

import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.rpc.RpcContext;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.ulife.base.entities.order.*;
import com.ulife.base.logics.order.*;
import com.ulife.cart.api.CartService;
import com.ulife.cart.api.response.*;
import com.ulife.common.gateway.utils.annotation.ApiParameter;
import com.ulife.common.gateway.utils.define.CommonParameter;
import com.ulife.common.gateway.utils.define.ExtendParameter;
import com.ulife.common.gateway.utils.define.Version;
import com.ulife.common.gateway.utils.entity.ServiceException;
import com.ulife.common.gateway.utils.responseEntity.RawString;
import com.ulife.common.utils.events.RedisEvent;
import com.ulife.common.utils.lang.JsonMapper;
import com.ulife.member.api.MemberService;
import com.ulife.member.api.response.address.CustomerAddressInfo;
import com.ulife.member.api.response.customer.CustomerDto;
import com.ulife.member.api.response.pay.AccountDebuctInfo;
import com.ulife.member.api.response.transaction.AccountBalance;
import com.ulife.order.api.response.PayRequest;
import com.ulife.order.api.OrderService;
import com.ulife.order.api.errors.OrderErrorCodes;
import com.ulife.order.api.response.ResponseMessage;
import com.ulife.order.api.response.cart.*;
import com.ulife.order.api.response.cms.OrderInfoResponse;
import com.ulife.order.api.response.cms.SaleOrderRefundInfo;
import com.ulife.order.api.response.cms.SoCommentsDTO;
import com.ulife.order.api.response.promotion.ProInfo;
import com.ulife.order.api.response.promotion.ProRules;
import com.ulife.order.components.core.refund.OrderRefund;
import com.ulife.order.components.mode.*;
import com.ulife.order.service.componentConst.SaleOrderTypeConst;
import com.ulife.order.api.core.refund.RefundStatus;
import com.ulife.order.service.domain.Order;
import com.ulife.order.service.domain.Schedule;
import com.ulife.order.service.domain.Yqf;
import com.ulife.order.service.dto.YqfTraceDTO;
import com.ulife.order.service.enumeration.*;
import com.ulife.order.service.util.JsonUtils;
import com.ulife.product.api.ProductService;
import com.ulife.product.api.resposne.delivery.ProductDeliveryResponse;
import com.ulife.product.api.resposne.payment.PayChannelDTO;
import com.ulife.product.api.resposne.payment.PayTypeResponse;
import com.ulife.product.api.resposne.productInfo.ItemDTO;
import com.ulife.product.api.resposne.productInfo.ProductMoreResponse;
import com.ulife.product.api.resposne.productInfo.SingleProductResponse;
import com.ulife.promo.api.PromoService;
import com.ulife.promo.api.response.PromoDiscount;
import com.ulife.promo.api.response.PromoInfo;
import com.ulife.order.service.componentConst.SaleOrderTypeConst;
import com.ulife.order.service.domain.Order;
import com.ulife.order.service.domain.Schedule;
import com.ulife.promo.api.response.PromoPayInfo;
import com.ulife.promo.api.response.PromoRules;
import com.ulife.promo.api.response_cms.PromoRule;
import com.ulife.promo.api.response_cms.Results;
import com.ulife.stock.api.StockService;
import com.ulife.stock.api.response.ProductStockResponse;
import com.ulife.stock.api.response.ProductsStockResponse;
import com.ulife.utils.config.MessageSender;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.ibatis.session.RowBounds;
import org.dozer.DozerBeanMapper;
import org.springframework.beans.factory.annotation.Autowired;
import com.ulife.order.api.response.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by Ulife on 2015/12/29
 */
@Component
@Service(version = Version.LATEST)
public class OrderComponent implements OrderService {


    @Autowired
    private Order order;
    @Autowired
    Yqf yqf;
    @Resource
    OrderRefund orderRefund;
    @Resource
    SaleOrderLogic saleOrderLogic;
    @Resource
    SaleOrderShipLogic saleOrderShipLogic;
    @Resource
    SaleOrderItemLogic saleOrderItemLogic;
    @Resource
    SaleOrderPayLogic saleOrderPayLogic;
    @Resource
    SoCommentsLogic soCommentsLogic;
    @Resource
    SaleOrderTrackingLogic saleOrderTrackingLogic;
    @Resource
    ShipmentOrderItemLogic shipmentOrderItemLogic;
    @Resource
    SaleOrderItemPromotionLogic saleOrderItemPromotionLogic;
    @Resource
    CpsTraceLogic cpsTraceLogic;
    @Resource
    SaleOrderRefundLogic saleOrderRefundLogic;
    @Resource
    DailyLimitLogic dailyLimitLogic;
    @Resource
    CustomerFirstSaleLogic customerFirstSaleLogic;
    @Resource
    Order orderDomain;
    @Resource
    Schedule schedule;
    @Resource
    DozerBeanMapper dozerBeanMapper;
    @Resource
    private RedisTemplate redisTemplate;
    //消息推送
    @Resource
    MessageSender messageSender;



    //---------------other Service-------------  ,registry = {"test"}
    @Reference(version = Version.LATEST)
    MemberService memberService;
    @Reference(version = Version.LATEST)
    CartService cartService;
    @Reference(version = Version.LATEST)
    ProductService productService;
    @Reference(version = Version.LATEST)
    PromoService promoService;
    @Reference(version = Version.LATEST)
    StockService stockService;

    @Value("${order.pay.CODico}")
    String payCODico;
    @Value("${order.pay.CODdescription}")
    String payCODdescription;
    @Value("${order.pay.error_page}")
    String payErrorPage;
    @Value("${order.pay.callback_url}")
    String payCallbackUrl;
    @Value("${order.pay.order_detail_url}")
    String payOrderDetailUrl;
    @Value("${order.pay.description}")
    String payDescription;
    @Value("${order.pay.Url}")
    String payUrl;
    @Value("${order.payRefund.Url}")
    String payRefundUrl;
    @Value("${order.maxorders}")
    Integer maxOrders;
    @Value("${order.pay.OnlinePayIcoUrl}")
    String payIcoUrl;
    @Value("${order.pay.refundChanelNo}")
    String refundChanelNo;





    private static JsonMapper Json = JsonMapper.nonDefaultMapper();
    Logger logger = LoggerFactory.getLogger(OrderService.class);

    StringRedisSerializer keySerializer = new StringRedisSerializer();

    //region--------------------------------------------下面是页面调用的接口-------------------------------------------------------------

    /**
     * 结算页信息
     *
     * @param items 商品
     * @return
     * @throws ServiceException
     */
    @Override
    public ConfirmInfo confirm(@ApiParameter(required = true, name = "items", desc = "商品信息 [{\"itemId\":100893,\"num\":1}]") String items,
                                @ApiParameter(required = false, name = "couponSelfId", desc = "自营优惠券ID") long couponSelfId,
                                @ApiParameter(required = false, name = "couponProviderId", desc = "直送优惠券ID") long couponProviderId
                               ) throws ServiceException {

        ConfirmInfo confirmInfo = new ConfirmInfo();

        //【公共参数】
        String customer_id = RpcContext.getContext().getAttachment(CommonParameter.userId);
        String terminal = RpcContext.getContext().getAttachment(ExtendParameter.terminal);

        //【地址信息】
        long defaultCityZoneId = 0; //默认地区id
        {
            List<CustomerAddressInfo> addresslist = new ArrayList<CustomerAddressInfo>();

            //会员服务获取用户地址列表
            try {
                addresslist = memberService.addressList(0);
            } catch (Exception ex) {
                logger.error("【会员服务|用户地址列表 in 结算页】（报错）");
                logger.error("【报错信息】customer_id=" + customer_id);
                logger.error(ex);
                throw new ServiceException(OrderErrorCodes.errorCodes_ADDRESSLIST_NOT_FOUND, "【会员服务|用户地址列表 in 结算页】（报错）");
            }

            if (addresslist != null && addresslist.size() != 0) {
                //用户地址信息列表
                List<AddressInfo> addressInfos = new ArrayList<AddressInfo>();
                for (CustomerAddressInfo customerAddressInfo : addresslist) {
                    //默认地址
                    if (customerAddressInfo.getIsDefault() == 1) {
                        defaultCityZoneId = customerAddressInfo.getCityZoneId();
                    }
                    AddressInfo addressInfo = new AddressInfo();
                    dozerBeanMapper.map(customerAddressInfo, addressInfo);
                    addressInfo.setAddressId(customerAddressInfo.getAddressId());
                    addressInfo.setMobile(customerAddressInfo.getMobileNo());
                    addressInfos.add(addressInfo);
                }

                //设置默认地址
                if (defaultCityZoneId == 0 && addressInfos != null && addressInfos.size() > 0) {
                    defaultCityZoneId = addressInfos.get(0).getCityZoneId();
                    addressInfos.get(0).setIsDefault(1);
                }

                //加入返回结果中
                confirmInfo.setAddresss(addressInfos);
            }
        }

        //【计算配送日期】
        try {
            List<ItemIdNumDTO> itemAll = Json.jsonToList(items, ItemIdNumDTO.class);
            StringBuffer sbfItem = new StringBuffer();
            for (ItemIdNumDTO itemIdNumDTO : itemAll) {
                if (sbfItem.length() != 0) {
                    sbfItem.append(",");
                }
                sbfItem.append(itemIdNumDTO.getItemId());
            }
            List<DeliveryDatesInfo> deliveryDatesInfos = getDeliveryDates(sbfItem.toString(), defaultCityZoneId);
            //加入返回结果
            confirmInfo.setDeliveryDates(deliveryDatesInfos);
        } catch (Exception ex) {
            logger.error("[配送日期 in 结算页] 报错");
            logger.error("【报错信息】 items=" + items);
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_DELIVERYDATES_ERROR, "[配送日期 in 结算页]" + ex.getMessage());
        }

        //【购物车商品信息】
        CartGetInfo cartGetInfo = null;
        try {
            RpcContext.getContext().setAttachment(CommonParameter.userId, customer_id);
            RpcContext.getContext().setAttachment(ExtendParameter.terminal, terminal);
            cartGetInfo = cartService.cartCalc(items);
        } catch (Exception ex) {
            logger.error("【购物车服务|根据商品获取信息 in 结算页】 报错");
            logger.error("【报错信息】 items=" + items);
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_CARTPRODUCT_NOT_FOUND, "【购物车服务|根据商品获取信息 in 结算页】 报错");
        }

        //获取 商品详情，优惠券详情，计算价格
        calculationOrder(customer_id, terminal, confirmInfo, true, true, true, couponSelfId, couponProviderId, cartGetInfo);

        //【设置支付方式】
        //是否有直发
        boolean hasZhiFa = false;
        if (confirmInfo != null && confirmInfo.getGroups() != null && confirmInfo.getGroups().size() > 0) {
            for (ItemGroupInfo itemGroupInfo : confirmInfo.getGroups()) {
                if (itemGroupInfo.getMode().equals("直发")) {
                    hasZhiFa = true;
                }
            }
        }
        List<PayTypeInfo> payTypeInfos = confirmPayTyps(hasZhiFa, defaultCityZoneId); //获取支付方式
        if (payTypeInfos != null && payTypeInfos.size() > 0) {
            confirmInfo.setPayTypes(payTypeInfos);
        }

        return confirmInfo;
    }

    /**
     * 设置支付方式
     *
     * @param hasZhifa
     * @param cityZoneId
     */
    private List<PayTypeInfo> confirmPayTyps(boolean hasZhifa, long cityZoneId) {
        List<PayTypeInfo> payTypeInfos = new ArrayList<PayTypeInfo>();
        PayTypeInfo payTypeInfo_online = new PayTypeInfo();
        payTypeInfo_online.setName("线上支付");
        payTypeInfo_online.setCode("ONLINE");
        payTypeInfos.add(payTypeInfo_online);

        //有直发则不能货到付款
        if (!hasZhifa && 310230 != cityZoneId) {
            PayTypeInfo payTypeInfo_cod = new PayTypeInfo();
            payTypeInfo_cod.setName("货到付款");
            payTypeInfo_cod.setCode("COD");
            payTypeInfos.add(payTypeInfo_cod);
        }
        return payTypeInfos;
    }

    /**
     * 获取配送日期&支付方式
     *
     * @param item_ids
     * @param address_id
     * @return
     * @throws ServiceException
     */
    @Override
    public DeliverDatesAndPayTypeInfos DeliveryDates(@ApiParameter(required = true, name = "item_ids", desc = "商品id集合 100893,100893,100893") String item_ids,
                                                     @ApiParameter(required = true, name = "address_id", desc = "地址id") long address_id) throws ServiceException {

        DeliverDatesAndPayTypeInfos rtn = new DeliverDatesAndPayTypeInfos();

        //公共参数
        String terminal = RpcContext.getContext().getAttachment(ExtendParameter.terminal);

        ArrayList<CustomerAddressInfo> list = null;
        try {
            list = memberService.addressList(address_id);
        } catch (Exception ex) {
            logger.error("【会员服务|用户地址列表 in 获取日期接口】（报错）");
            logger.error("【报错信息】address_id=" + address_id);
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_ADDRESSLIST_NOT_FOUND, "【会员服务|用户地址列表 in 获取日期接口】（报错）");
        }

        if (list == null || list.size() == 0) {
            return null;
        }
        CustomerAddressInfo addressInfo = list.get(0);
        List<DeliveryDatesInfo> deliveryDatesInfos = getDeliveryDates(item_ids, addressInfo.getCityZoneId());
        if (deliveryDatesInfos != null && deliveryDatesInfos.size() > 0) {
            rtn.setDeliveryDatesInfos(deliveryDatesInfos);
        }

        //支付方式
        //查询是否有直发商品
        boolean hanZhifa = false;
        if (item_ids != null && !item_ids.isEmpty()) {
            String[] ids = item_ids.split(",");
            if (ids != null && ids.length > 0) {
                for (String id : ids) {
                    try {
                        RpcContext.getContext().setAttachment(ExtendParameter.terminal, terminal);
                        SingleProductResponse response = productService.get(Long.parseLong(id));
                        String itemForm = response.getItem().getProductForm().toUpperCase();
                        if (!itemForm.equals("SELF")) {
                            hanZhifa = true;
                        }
                    } catch (Exception ex) {
                        logger.error("【商品服务|获取商品详情 in 获取日期&支付方式接口】（报错）");
                        logger.error("【报错信息】address_id=" + address_id + " item_ids=" + item_ids);
                        logger.error(ex);
                        throw new ServiceException(OrderErrorCodes.errorCodes_ADDRESSLIST_NOT_FOUND, "【商品服务|获取商品详情 in 获取日期&支付方式接口】（报错）");
                    }
                }
            }
        }
        List<PayTypeInfo> payTypeInfos = confirmPayTyps(hanZhifa, addressInfo.getCityZoneId());
        if (payTypeInfos != null && payTypeInfos.size() > 0) {
            rtn.setPayTypeInfos(payTypeInfos);
        }
        return rtn;
    }

    /**
     * 计算配送日期
     *
     * @param items
     * @param cityZoneId
     * @return
     * @throws ServiceException
     */
    private List<DeliveryDatesInfo> getDeliveryDates(String items, Long cityZoneId) throws ServiceException {

        //商品服务可选日期范围
        ProductDeliveryResponse productDeliveryResponse = getDeliveryByProduct(items);
        //开始配送时间计算
        Calendar instance = getBeginDeliveryDate(cityZoneId);

        //构建可选日期
        List<DeliveryDatesInfo> deliveryDatesInfos = new ArrayList<DeliveryDatesInfo>();
        //执行次数
        int calculateTimes = 0;
        //日期格式化
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        do {

            DeliveryDatesInfo deliveryDatesInfo = new DeliveryDatesInfo();

            //开始时间 转化
            long shipDate = 0;
            try {
                String shipdate_s = sdf.format(instance.getTime());
                Date shipDate_d = sdf.parse(shipdate_s);
                shipDate = shipDate_d.getTime();
            } catch (Exception ex) {
                logger.error("[计算配送时间 in 计算配送日期] 报错 开始时间转化报错");
                logger.error(ex);
                throw new ServiceException(OrderErrorCodes.errorCodes_PRODUCTDELIVERYLIST_NOT_FOUND, "[计算配送时间 in 计算配送日期] 报错 开始时间转化报错");
            }

            //限单查询
            boolean isCanShip = isDaliyLimit(instance.getTime());

            if (!isCanShip) {
                deliveryDatesInfo.setDate(shipDate);
                deliveryDatesInfo.setMessage("配送量已满");
                deliveryDatesInfo.setEnable(false);
            } else {
                productDeliveryDateCheckShipDate(productDeliveryResponse, deliveryDatesInfo, shipDate);

                //如果日期不可配送了
                /*if (deliveryDatesInfo.getMessage().equals("配送时间小于开始时间")||deliveryDatesInfo.getMessage().equals("配送时间大于结束时间"))
                {
                    deliveryDatesInfos.add(deliveryDatesInfo);//test2
                }*/
            }

            //可用的日期返回
            if (deliveryDatesInfo.isEnable() == true) {
                deliveryDatesInfos.add(deliveryDatesInfo);
            }

            instance.add(Calendar.DATE, 1); // 在加上1天
            calculateTimes++;

            if (calculateTimes == 50) {
                logger.info("[计算配送时间结果 in 计算配送日期] （失败） 可配送日期不够");
                logger.info("[详细信息] firstDate:" + productDeliveryResponse.firstDate + "  lastdDate：" + productDeliveryResponse.lastDate);
            }
        }
        while (deliveryDatesInfos.size() < 7 && calculateTimes < 50);
        return deliveryDatesInfos;
    }

    /**
     * 校验时间是否可配送
     *
     * @param CityZoneId
     * @param items
     * @param deliveryDate
     * @return
     * @throws ServiceException
     */
    private boolean checkDeliveryDatebyProduct(long CityZoneId, String items, long deliveryDate) throws ServiceException {
        boolean rtn = false;

        //【限单校验】
        //查询日单量
        boolean isdaliy = isDaliyLimit(new Date(deliveryDate));
        if (!isdaliy) {
            return rtn;
        }

        //开始时间
        Calendar instance = getBeginDeliveryDate(CityZoneId);

        //商品服务可选日期范围
        ProductDeliveryResponse productDeliveryResponse = getDeliveryByProduct(items);

        DeliveryDatesInfo deliveryDatesInfo = new DeliveryDatesInfo();
        //开始时间 转化
        long shipDate = 0;
        try {
            //日期格式化
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String shipdate_s = sdf.format(instance.getTime());
            Date shipDate_d = sdf.parse(shipdate_s);
            shipDate = shipDate_d.getTime();
        } catch (Exception ex) {
            logger.error("[计算配送时间 in 计算配送日期] 报错 开始时间转化报错");
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_PRODUCTDELIVERYLIST_NOT_FOUND, "[计算配送时间 in 计算配送日期] 报错 开始时间转化报错");
        }

        if (deliveryDate < shipDate) {
            rtn = false;
            return rtn;
        }

        productDeliveryDateCheckShipDate(productDeliveryResponse, deliveryDatesInfo, deliveryDate);

        //如果日期不可配送了，直接返回
        rtn = deliveryDatesInfo.isEnable();

        return rtn;
    }

    /**
     * 当初始化单量配送
     *
     * @return
     * @throws ServiceException
     */
    @Override
    public boolean DaliyLimitCache() throws ServiceException {
        boolean rtn = false;
        //去缓存中查当日可用订单量

        Calendar instance = Calendar.getInstance();//时间

        //从当前时间开始60天内的可配送数
        for (int i = 0; i < 60; i++) {
            String dateStr = new SimpleDateFormat("yyyy-MM-dd").format(instance.getTime());


            //【当日的单量】
            String dateStr_s = dateStr + " 00:00:00";
            String dateStr_e = dateStr + " 23:23:59";
            Date time_s = null;
            Date time_e = null;
            try {
                time_s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr_s);
                time_e = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr_e);
            } catch (Exception ex) {
                logger.error("[每日限单时间组装失败 in 每日配送量验证]");
                logger.error(ex);
                throw new ServiceException(OrderErrorCodes.errorCodes_PRODUCTDELIVERYLIST_NOT_FOUND, "[每日限单时间组装失败 in 每日配送量验证]");
            }

            int OrderDateCount = 0; //当日单量
            try {
                SaleOrderCriteria criteria = new SaleOrderCriteria();
                criteria.createCriteria()
                        .andOrderTypeEqualTo("main")
                        .andShipDateBetween(time_s, time_e)
                        .andStatusNotEqualTo(SaleOrderStatus.Cancel.value());
                OrderDateCount = saleOrderLogic.count(criteria);
            } catch (Exception ex) {
                logger.error("[查询每日单量失败 in 计算配送日期]");
                logger.error("[报错信息] time_s=" + time_s + " time_e=" + time_e);
                throw new ServiceException(OrderErrorCodes.errorCodes_PRODUCTDELIVERYLIST_NOT_FOUND, "[查询每日单量失败 in 计算配送日期]");
            }

            //当日配送单量
            int dailyCount = 0;
            DailyLimitCriteria criteria = new DailyLimitCriteria();
            criteria.createCriteria().andDateEqualTo(instance.getTime());
            List<DailyLimit> dailyLimits = null;
            try {
                dailyLimits = dailyLimitLogic.list(criteria);

            } catch (Exception ex) {
                logger.error("[限单获取|获取限单配置信息 in 获取限单信息方法] 报错");
                logger.error("[报错信息] date=" + instance.getTime());
                logger.error(ex);
                throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_daliylimit_ERROR, "[限单获取|获取限单配置信息 in 获取限单信息方法] 报错");
            }
            if (dailyLimits != null && dailyLimits.size() > 0) {
                dailyCount = dailyLimits.get(0).getCount();
            }
            if (dailyCount == 0) {
                dailyCount = maxOrders;
            }


            //改天的可用配送量= 限制总单-日单量
            int candaliy = dailyCount - OrderDateCount;
            if (candaliy < 0) {
                candaliy = 0;
            }
            ;

            final Integer icandaliy = candaliy;

            redisTemplate.execute((RedisCallback) connection -> {
                connection.hSet(keySerializer.serialize("orderlimit"), keySerializer.serialize(dateStr), keySerializer.serialize(String.valueOf(icandaliy) + ""));
                return null;
            });

            //加一天
            instance.add(Calendar.DATE, 1); // 在加上1天
        }
        //加入
        return rtn;
    }

    /**
     * 给某天加1配送量
     *
     * @param date
     */
    private void addDaliyLimitCache(Date date) {
        String dateStr = new SimpleDateFormat("yyyy-MM-dd").format(date);
        redisTemplate.execute((RedisCallback) connection -> {
            connection.hIncrBy(keySerializer.serialize("orderlimit"), keySerializer.serialize(dateStr), 1);
            return true;
        });
    }

    /**
     * 给某天减1配送量
     *
     * @param date
     */
    private void delDaliyLimitCache(Date date) {
        String dateStr = new SimpleDateFormat("yyyy-MM-dd").format(date);
        redisTemplate.execute((RedisCallback) connection -> {
            connection.hIncrBy(keySerializer.serialize("orderlimit"), keySerializer.serialize(dateStr), -1);
            return true;
        });
    }


    /**
     * 根据日期获取配送单量
     *
     * @param date
     * @return
     */
    private boolean isDaliyLimit(Date date) throws ServiceException {

        boolean rtn = false;

        String dateStr = new SimpleDateFormat("yyyy-MM-dd").format(date);

        Object booleanObj = redisTemplate.execute((RedisCallback) connection -> {
            byte[] rawValue = connection.hGet(keySerializer.serialize("orderlimit"), keySerializer.serialize(dateStr));
            if (rawValue != null) {
                Integer value = Integer.parseInt(new String(keySerializer.deserialize(rawValue)));
                return value;
            }
            return 0;
        });

        int cancount = (int) booleanObj;
        rtn = cancount > 0;

        /*//【限单校验】
        //查询日单量
        String dateStr = new SimpleDateFormat("yyyy-MM-dd").format(date);
        String dateStr_s = dateStr + " 00:00:00";
        String dateStr_e = dateStr + " 23:23:59";
        Date time_s = null;
        Date time_e = null;
        try {
            time_s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr_s);
            time_e = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr_e);
        } catch (Exception ex) {
            logger.error("[每日限单时间组装失败 in 每日配送量验证]");
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_PRODUCTDELIVERYLIST_NOT_FOUND,"[每日限单时间组装失败 in 每日配送量验证]");
        }

        //当日的单量
        int OrderDateCount =0;
        try
        {
            SaleOrderCriteria criteria = new SaleOrderCriteria();
            criteria.createCriteria()
                    .andOrderTypeEqualTo("main")
                    .andShipDateBetween(time_s, time_e)
                    .andStatusNotEqualTo(SaleOrderStatus.Cancel.value());
            OrderDateCount= saleOrderLogic.count(criteria);
        }
        catch (Exception ex)
        {
            logger.error("[查询每日单量失败 in 计算配送日期]");
            logger.error("[报错信息] time_s="+time_s+" time_e="+time_e);
            throw new ServiceException(OrderErrorCodes.errorCodes_PRODUCTDELIVERYLIST_NOT_FOUND,"[查询每日单量失败 in 计算配送日期]");
        }

        int dailyCount = 0;
        DailyLimitCriteria criteria = new DailyLimitCriteria();
        criteria.createCriteria().andDateEqualTo(date);
        List<DailyLimit> dailyLimits = null;
        try {
            dailyLimits = dailyLimitLogic.list(criteria);

        }catch (Exception ex)
        {
            logger.error("[限单获取|获取限单配置信息 in 获取限单信息方法] 报错");
            logger.error("[报错信息] date="+date.toString());
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_daliylimit_ERROR,"[限单获取|获取限单配置信息 in 获取限单信息方法] 报错");
        }
        if (dailyLimits!=null&&dailyLimits.size()>0)
        {
            dailyCount = dailyLimits.get(0).getCount();
        }

        if (dailyCount==0)
        {
            dailyCount = maxOrders;
        }

        logger.debug("每日单量：" + OrderDateCount + "   配送单量：" + dailyCount);
        rtn = OrderDateCount < dailyCount;*/

        return rtn;
    }

    /**
     * 获取商品的配送日期
     *
     * @param items
     * @return
     * @throws ServiceException
     */
    private ProductDeliveryResponse getDeliveryByProduct(String items) throws ServiceException {
        ProductDeliveryResponse productDeliveryResponse = null;
        try {
            productDeliveryResponse = productService.getDeliveryByProduct(items);
        } catch (Exception ex) {
            logger.error("【商品服务|根据商品获取配送日期 in 计算配送日期】报错");
            logger.error("【报错信息】 items=" + items);
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_PRODUCTDELIVERYLIST_NOT_FOUND, "【商品服务|根据商品获取配送日期 in 计算配送日期】报错");
        }
        return productDeliveryResponse;
    }

    /**
     * 根据商品配送日期校验配送日期
     *
     * @param productDeliveryResponse
     * @param deliveryDatesInfo
     * @param shipDate
     */
    private void productDeliveryDateCheckShipDate(ProductDeliveryResponse productDeliveryResponse, DeliveryDatesInfo deliveryDatesInfo, long shipDate) {
        long firstDate = productDeliveryResponse.firstDate;
        long endDate = productDeliveryResponse.lastDate;
        if (firstDate == 0 && endDate == 0) {
            //如果配送时间没有限制，OK
            deliveryDatesInfo.setDate(shipDate);
            deliveryDatesInfo.setMessage("可配送");
            deliveryDatesInfo.setEnable(true);
        } else if (shipDate < firstDate && firstDate != 0) {
            //配送时间小于开始时间,NO OK
            deliveryDatesInfo.setDate(shipDate);
            deliveryDatesInfo.setMessage("配送时间小于开始时间");
            deliveryDatesInfo.setEnable(false);
        } else if (shipDate > endDate && endDate != 0) {
            //配送时间大于结束时间，NO OK
            deliveryDatesInfo.setDate(shipDate);
            deliveryDatesInfo.setMessage("配送时间大于结束时间");
            deliveryDatesInfo.setEnable(false);
        } else {
            deliveryDatesInfo.setDate(shipDate);
            deliveryDatesInfo.setMessage("可配送");
            deliveryDatesInfo.setEnable(true);
        }
    }

    /**
     * 开始配送时间
     *
     * @param cityZoneId
     * @return
     */
    private Calendar getBeginDeliveryDate(long cityZoneId) {
        Calendar instance = Calendar.getInstance();
        //根据接单时间却确定开始配送时间
        int lastHour = 21;  //截单时间点  可优化
        if (instance.get(Calendar.HOUR_OF_DAY) >= lastHour) {
            instance.add(Calendar.DATE, 2);
        } else {
            instance.add(Calendar.DATE, 1);
        }
        //地址校验  崇明地区再加1天
        if (310230 == cityZoneId) {
            instance.add(Calendar.DATE, 1);
        }
        return instance;
    }

    /**
     * 计算订单价格
     *
     * @param items
     * @param coupon_self_id
     * @param coupon_provider_id
     * @return
     * @throws ServiceException
     */
    @Override
    public ConfirmInfo calculate(@ApiParameter(required = true, name = "items", desc = "商品信息 [{\"itemId\":100893,\"num\":1}]") String items,
                                 @ApiParameter(required = true, name = "coupon_self_id", desc = "自营优惠券ID") String coupon_self_id,
                                 @ApiParameter(required = true, name = "coupon_provider_id", desc = "直发优惠券ID") String coupon_provider_id) throws ServiceException {

        //公共参数
        String customer_id = RpcContext.getContext().getAttachment(CommonParameter.userId);
        String terminal = RpcContext.getContext().getAttachment(ExtendParameter.terminal);

        //返回结果
        ConfirmInfo confirmInfo = new ConfirmInfo();

        //【购物车商品信息】
        CartGetInfo cartGetInfo = null;
        try {
            RpcContext.getContext().setAttachment(CommonParameter.userId, customer_id);
            RpcContext.getContext().setAttachment(ExtendParameter.terminal, terminal);
            cartGetInfo = cartService.cartCalc(items);
        } catch (Exception ex) {
            logger.error("【购物车服务|根据商品获取信息 in 订单价格计算】 报错");
            logger.error("【报错信息】 items=" + items);
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_CARTPRODUCT_NOT_FOUND, "【购物车服务|根据商品获取信息 in 订单价格计算】 报错");
        }


        //价格计算
        calculationOrder(customer_id, terminal, confirmInfo, true, false, false, Long.parseLong(coupon_self_id), Long.parseLong(coupon_provider_id), cartGetInfo);

        //去除商品信息
        //计算价格时，必须整理正品信息，返回时去除商品信息
        for (ItemGroupInfo itemGroupInfo : confirmInfo.getGroups()) {
            itemGroupInfo.setItems(null);
        }

        return confirmInfo;
    }

    /**
     * 创建订单
     *
     * @param address_id
     * @param coupon_self_id
     * @param coupon_provider_id
     * @param ship_date
     * @param items
     * @param pay_type
     * @return
     * @throws ServiceException
     */
    @Override
    public OrderStatusInfo create(@ApiParameter(required = true, name = "address_id", desc = "地址ID") int address_id,
                                  @ApiParameter(required = true, name = "coupon_self_id", desc = "自营优惠券ID") String coupon_self_id,
                                  @ApiParameter(required = true, name = "coupon_provider_id", desc = "自营优惠券ID") String coupon_provider_id,
                                  @ApiParameter(required = false, name = "ship_date", desc = "配送日期") long ship_date,
                                  @ApiParameter(required = true, name = "items", desc = "商品信息 [{\"itemId\":100893,\"num\":1}]") String items,
                                  @ApiParameter(required = true, name = "pay_type", desc = "货到付款：COD，在线支付：ONLINE") String pay_type) throws ServiceException {

        //【公共参数】
        //用户id
        String customer_id = RpcContext.getContext().getAttachment(CommonParameter.userId);
        //Terminal
        String terminal = RpcContext.getContext().getAttachment(ExtendParameter.terminal);
        //deviceId
        String deviceId = RpcContext.getContext().getAttachment(ExtendParameter.idfa);
        //src
        String src = RpcContext.getContext().getAttachment(ExtendParameter.src);


        logger.error("src = " + src == null ? "null" : src);
        //emar_source
        String emar_source = RpcContext.getContext().getAttachment(ExtendParameter.emar_source);
        logger.error("emar_source = " + emar_source == null ? "null" : emar_source);
        //emar_channel
        String emar_channel = RpcContext.getContext().getAttachment(ExtendParameter.emar_channel);
        logger.error("emar_channel = " + emar_channel == null ? "null" : emar_channel);
        //emar_cid
        String emar_cid = RpcContext.getContext().getAttachment(ExtendParameter.emar_cid);
        logger.error("emar_cid = " + emar_cid == null ? "null" : emar_cid);
        //emar_wi
        String emar_wi = RpcContext.getContext().getAttachment(ExtendParameter.emar_wi);
        logger.error("emar_wi = " + emar_wi == null ? "null" : emar_wi);

        Map<String,String> emar = new HashMap<>();
        emar.put(ExtendParameter.emar_source,emar_source);
        emar.put(ExtendParameter.emar_channel,emar_channel);
        emar.put(ExtendParameter.emar_cid,emar_cid);
        emar.put(ExtendParameter.emar_wi,emar_wi);

        //now
        Date now = new Date();

        long coupon_self_id_i = 0;
        if (coupon_self_id != null && !coupon_self_id.isEmpty()) {
            coupon_self_id_i = Long.parseLong(coupon_self_id);
        }
        long coupon_provider_id_i = 0;
        if (coupon_provider_id != null && !coupon_provider_id.isEmpty()) {
            coupon_provider_id_i = Long.parseLong(coupon_provider_id);
        }

        //获取商品信息
        CartGetInfo cartGetInfo = null;
        try {
            cartGetInfo = cartService.cartCalc(items);
            logger.debug("[购物车服务|根据商品获取信息] 购物车返回信息 =" + Json.toJson(cartGetInfo));
        } catch (Exception ex) {
            logger.error("【购物车服务|根据商品获取信息 in 订单提交页】 报错");
            logger.error("【报错信息】 items=" + items);
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_CARTPRODUCT_NOT_FOUND, "【购物车服务|根据商品获取信息 in 订单提交页】 报错 exMsg=" + ex.getMessage());
        }

        //订单信息
        ConfirmInfo confirmInfo = new ConfirmInfo();

        //计算订单价格
        CalculationDTO calculationDTO = calculationOrder(customer_id, terminal, confirmInfo, true, false, false, coupon_self_id_i, coupon_provider_id_i, cartGetInfo);

        String generateOrderNo = "";
        try {
            generateOrderNo = memberService.generateOrderNo();
        } catch (Exception ex) {
            logger.error("【会员服务|生成订单号 in 订单创建页】 报错");
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_GENERATE_ORDERNO_ERROR, "【会员服务|生成订单号 in 订单创建页】 报错 exMsg= " + ex.getMessage());
        }

        //构建主订单信息
        SaleOrder saleOrder = new SaleOrder();
        saleOrder.setSaleNo(generateOrderNo);
        saleOrder.setCustomerId(Long.parseLong(customer_id));
        saleOrder.setOrderTime(now);
        saleOrder.setOrderType(SaleOrderTypeConst.MAIN_SALE_ORDER);
        saleOrder.setSaleChannel("ONLINE");
        saleOrder.setSource("");
        saleOrder.setSrc(src);
        saleOrder.setTerminal(terminal);
        saleOrder.setShipStatus(SaleOrderShipStatus.WaitShip.value());
        saleOrder.setPaidAmount(new BigDecimal("0"));
        saleOrder.setPayStatus(SaleOrderPayStatus.WaitPay.value());
        saleOrder.setOrderCategory("普通订单");
        saleOrder.setGroupId(0l);   //不是团购订单，团购id默认为0
        saleOrder.setSplitEnable(1);  //订单是否可拆  0：不可以  1：可以
        saleOrder.setCreatedBy("system");
        saleOrder.setCreatedTime(now);
        saleOrder.setModifiedBy("system");
        saleOrder.setModifiedTime(now);
        saleOrder.setStatus(SaleOrderStatus.Created.value());
        saleOrder.setVersion(1);
        saleOrder.setShipDate(new Date(ship_date));
        if (pay_type.equals("COD")) {
            saleOrder.setPayType("货到付款");
            saleOrder.setPayChannel("货到付款");
        } else if (pay_type.equals("ONLINE")) {
            saleOrder.setPayType("线上支付");
        }

        //费用赋值
        saleOrder.setSubAmount(new BigDecimal(confirmInfo.getCalculation().getSubAmount()));
        saleOrder.setPromotionDiscount(new BigDecimal(confirmInfo.getCalculation().getPromotionDiscount()));
        saleOrder.setProductCouponDiscount(new BigDecimal(confirmInfo.getCalculation().getProductCouponDiscount()));
        saleOrder.setShipFee(new BigDecimal(confirmInfo.getCalculation().getShipFee()));
        saleOrder.setShipFeeDiscount(new BigDecimal(confirmInfo.getCalculation().getShipFeeDiscount()));
        saleOrder.setShipFeeCouponDiscount(new BigDecimal(confirmInfo.getCalculation().getShipFeeCouponDiscount()));
        saleOrder.setTotalAmount(new BigDecimal(confirmInfo.getCalculation().getTotalAmount()));

        //构建订单商品信息
        List<SaleOrderItem> saleOrderItemList = new ArrayList<SaleOrderItem>();
        List<ItemGroupInfo> itemGroupInfos = confirmInfo.getGroups();
        for (ItemGroupInfo itemGroupInfo : itemGroupInfos) {
            List<ItemInfo> itemInfos = itemGroupInfo.getItems();
            for (ItemInfo itemInfo : itemInfos) {
                SaleOrderItem saleOrderItem = new SaleOrderItem();
                saleOrderItem.setSoNo(saleOrder.getSaleNo());
                saleOrderItem.setItemId(itemInfo.getItemId());
                saleOrderItem.setItemTitle(itemInfo.getItemTitle());
                saleOrderItem.setImgUrl(itemInfo.getImgUrl());
                saleOrderItem.setQuantity(itemInfo.getQuantity());
                if (itemInfo.getIsGift() == true) {
                    saleOrderItem.setUnitPrice(new BigDecimal(0));
                    saleOrderItem.setOrignalUnitPrice(new BigDecimal(0));
                } else {
                    saleOrderItem.setUnitPrice(new BigDecimal(itemInfo.getUnitPrice()));
                    saleOrderItem.setOrignalUnitPrice(new BigDecimal(itemInfo.getUnitPrice()));
                }
                saleOrderItem.setWeight(new BigDecimal(itemInfo.getWeight()));
                saleOrderItem.setModifiedBy("system");
                saleOrderItem.setModifiedTime(now);
                saleOrderItem.setCreatedBy("system");
                saleOrderItem.setCreatedTime(now);
                //mode
                String Mode = "";
                if (itemGroupInfo.getMode().equals("自营")) {
                    Mode = "SELF";
                } else if (itemGroupInfo.getMode().equals("直发")) {
                    Mode = "CONSIGNATION";
                }
                saleOrderItem.setItemForm(Mode);
                //item more info
                ProductMoreResponse productMore = null;
                try {
                    RpcContext.getContext().setAttachment(ExtendParameter.terminal, terminal);
                    productMore = productService.getMoreInfo(itemInfo.getItemId());
                } catch (Exception ex) {
                    logger.error("【商品服务|获取商品More in 创建订单接口】 报错");
                    logger.error("【报错信息】 ItemId=" + itemInfo.getItemId());
                    logger.error(ex);
                    throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_PRODUCT_SERVICE_ERROR, "【商品服务|获取商品More in 创建订单接口】 报错 ItemId=" + itemInfo.getItemId() + " exmsg=" + ex.getMessage());
                }
                saleOrderItem.setItemSupplier(Long.toString(productMore.getSalerId()));
                saleOrderItem.setSkuId(productMore.getSkuId());
                saleOrderItem.setSkuCode(productMore.getProductCode());
                saleOrderItem.setSkuName(productMore.getSkuName());
                saleOrderItem.setSkuCategoryId(productMore.getSkuCategoryId());
                saleOrderItem.setSkuCategoryName(productMore.getSkuCategoryName());
                saleOrderItem.setWeight(new BigDecimal(productMore.getWeight()));
                saleOrderItem.setVersion(1);
                saleOrderItemList.add(saleOrderItem);
            }
        }

        return createOrder(deviceId, customer_id, address_id, saleOrder, saleOrderItemList, cartGetInfo, calculationDTO,emar);
    }

    /**
     * 根据商品及信息，创建订单
     *
     * @param customer_id
     * @param src
     * @param terminal
     * @param deviceId
     * @param group_id
     * @param pay_type
     * @param address_id
     * @param orderCategory
     * @param shipfee
     * @param items
     * @return
     * @throws ServiceException
     */
    private OrderStatusInfo createOrderByItemInfo(String customer_id, String src, String terminal, String deviceId, long group_id, String pay_type, long address_id, String orderCategory, double shipfee, List<CreateItemDTO> items) throws ServiceException {
        //now
        Date now = new Date();
        //emar_source
        String emar_source = RpcContext.getContext().getAttachment(ExtendParameter.emar_source);
        logger.error("emar_source = " + emar_source == null ? "null" : emar_source);
        //emar_channel
        String emar_channel = RpcContext.getContext().getAttachment(ExtendParameter.emar_channel);
        logger.error("emar_channel = " + emar_channel == null ? "null" : emar_channel);
        //emar_cid
        String emar_cid = RpcContext.getContext().getAttachment(ExtendParameter.emar_cid);
        logger.error("emar_cid = " + emar_cid == null ? "null" : emar_cid);
        //emar_wi
        String emar_wi = RpcContext.getContext().getAttachment(ExtendParameter.emar_wi);
        logger.error("emar_wi = " + emar_wi == null ? "null" : emar_wi);

        Map<String,String> emar = new HashMap<>();
        emar.put(ExtendParameter.emar_source,emar_source);
        emar.put(ExtendParameter.emar_channel,emar_channel);
        emar.put(ExtendParameter.emar_cid,emar_cid);
        emar.put(ExtendParameter.emar_wi,emar_wi);

        String generateOrderNo = "";
        try {
            generateOrderNo = memberService.generateOrderNo();
        } catch (Exception ex) {
            logger.error("【会员服务|生成订单号 in 根据商品订单创建页】 报错");
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_GENERATE_ORDERNO_ERROR, "【会员服务|生成订单号 in 根据商品订单创建页】 报错");
        }

        //构建主订单信息
        SaleOrder saleOrder = new SaleOrder();
        saleOrder.setSaleNo(generateOrderNo);
        saleOrder.setCustomerId(Long.parseLong(customer_id));
        saleOrder.setOrderTime(now);
        saleOrder.setOrderType(SaleOrderTypeConst.MAIN_SALE_ORDER);
        saleOrder.setSaleChannel("ONLINE");
        saleOrder.setSource("");
        saleOrder.setSrc(src);
        saleOrder.setTerminal(terminal);
        saleOrder.setShipDate(new Date(0));
        saleOrder.setShipStatus(SaleOrderShipStatus.WaitShip.value());
        saleOrder.setPaidAmount(new BigDecimal("0"));
        saleOrder.setPayStatus(SaleOrderPayStatus.WaitPay.value());
        saleOrder.setOrderCategory(orderCategory);
        saleOrder.setGroupId(group_id);

        saleOrder.setConfirmTime(now);
        saleOrder.setCreatedBy("system");
        saleOrder.setCreatedTime(now);
        saleOrder.setModifiedBy("system");
        saleOrder.setModifiedTime(now);
        saleOrder.setStatus(SaleOrderStatus.Created.value());
        saleOrder.setVersion(1);
        saleOrder.setShipDate(new Date(0));
        if (pay_type.equals("COD")) {
            saleOrder.setPayType("货到付款");
        } else if (pay_type.equals("ONLINE")) {
            saleOrder.setPayType("线上支付");
        }

        //是否可拆单
        if (orderCategory.equals("虚拟商品订单") || orderCategory.equals("团购订单")) {
            saleOrder.setSplitEnable(0); //订单是否可拆  0：不可以  1：可以
        } else {
            saleOrder.setSplitEnable(1);
        }


        //费用计算
        saleOrder.setPromotionDiscount(new BigDecimal(0));
        saleOrder.setProductCouponDiscount(new BigDecimal(0));
        saleOrder.setShipFee(new BigDecimal(shipfee));
        saleOrder.setShipFeeDiscount(new BigDecimal(0));
        saleOrder.setShipFeeCouponDiscount(new BigDecimal(0));

        //构建订单商品信息
        BigDecimal totalAmount = new BigDecimal(0);
        List<SaleOrderItem> saleOrderItemList = new ArrayList<SaleOrderItem>();
        if (items != null && items.size() > 0) {
            for (CreateItemDTO createItemDTO : items) {
                long itemId = createItemDTO.getItemId();
                SaleOrderItem saleOrderItem = new SaleOrderItem();
                saleOrderItem.setSoNo(saleOrder.getSaleNo());
                saleOrderItem.setItemId(itemId);
                saleOrderItem.setQuantity(Integer.parseInt(String.valueOf(createItemDTO.getNum())));
                saleOrderItem.setModifiedBy("system");
                saleOrderItem.setModifiedTime(now);
                saleOrderItem.setCreatedBy("system");
                saleOrderItem.setCreatedTime(now);

                //item
                SingleProductResponse singleProductResponse = null;
                try {
                    RpcContext.getContext().setAttachment(ExtendParameter.terminal, terminal);
                    singleProductResponse = productService.get(itemId);
                } catch (Exception ex) {
                    logger.error("【商品服务|获取商品get in 团购创建订单接口】 报错");
                    logger.error("【报错信息】 ItemId=" + itemId);
                    logger.error(ex);
                    throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_PRODUCT_SERVICE_ERROR, "【商品服务|获取商品get in 团购创建订单接口】 报错 exmsg=" + ex.getMessage());
                }
                ItemDTO itemInfo = singleProductResponse.getItem();
                saleOrderItem.setItemTitle(itemInfo.getTitle());
                List<String> mediaInfos = itemInfo.getMediaInfos();
                saleOrderItem.setImgUrl((mediaInfos != null && mediaInfos.size() > 0) ? mediaInfos.get(0) : "");
                saleOrderItem.setUnitPrice(new BigDecimal(createItemDTO.getPrice()));
                saleOrderItem.setOrignalUnitPrice(new BigDecimal(createItemDTO.getPrice()));
                saleOrderItem.setItemForm(itemInfo.getProductForm().toUpperCase());
                saleOrderItem.setPublicWesen(itemInfo.getWesen()); //oto

                //item more info
                ProductMoreResponse productMore = null;
                try {
                    RpcContext.getContext().setAttachment(ExtendParameter.terminal, terminal);
                    productMore = productService.getMoreInfo(itemId);
                } catch (Exception ex) {
                    logger.error("【商品服务|获取商品More in 团购创建订单接口】 报错");
                    logger.error("【报错信息】 ItemId=" + itemId);
                    logger.error(ex);
                    throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_PRODUCT_SERVICE_ERROR, "【商品服务|获取商品More in 团购创建订单接口】 报错 exmsg=" + ex.getMessage());
                }
                saleOrderItem.setSkuId(productMore.getSkuId());
                saleOrderItem.setSkuCode(productMore.getProductCode());
                saleOrderItem.setSkuName(productMore.getSkuName());
                saleOrderItem.setSkuCategoryId(productMore.getSkuCategoryId());
                saleOrderItem.setSkuCategoryName(productMore.getSkuCategoryName());
                saleOrderItem.setWeight(new BigDecimal(productMore.getWeight()));
                saleOrderItem.setVersion(1);
                saleOrderItemList.add(saleOrderItem);
                totalAmount = totalAmount.add(saleOrderItem.getUnitPrice().multiply(new BigDecimal(saleOrderItem.getQuantity())));
            }
        }

        saleOrder.setSubAmount(totalAmount);
        saleOrder.setTotalAmount(totalAmount.add(new BigDecimal(shipfee)));

        return createOrder(deviceId, customer_id, address_id, saleOrder, saleOrderItemList, null, null,emar);
    }

    /**
     * 创建团购订单
     *
     * @param pay_type
     * @param items
     * @param address_id
     * @param group_id
     * @return
     * @throws ServiceException
     */
    @Override
    public OrderStatusInfo groupCreate(@ApiParameter(required = true, name = "pay_type", desc = "货到付款：COD，在线支付：ONLINE") String pay_type,
                                       @ApiParameter(required = true, name = "items", desc = "商品信息 [{\"itemId\":100893,\"num\":1}]") String items,
                                       @ApiParameter(required = true, name = "address_id", desc = "地址ID") int address_id,
                                       @ApiParameter(required = true, name = "group_id", desc = "团购ID") long group_id,
                                       @ApiParameter(required = true, name = "price", desc = "单价") double price) throws ServiceException {

        //【公共参数】
        //用户id
        String customer_id = RpcContext.getContext().getAttachment(CommonParameter.userId);
        //Terminal
        String terminal = RpcContext.getContext().getAttachment(ExtendParameter.terminal);
        //deviceId
        String deviceId = RpcContext.getContext().getAttachment(ExtendParameter.idfa);
        //src
        String src = RpcContext.getContext().getAttachment(ExtendParameter.src);

        //入参商品信息
        List<ItemIdNumDTO> itemIdNumDTOs = Json.jsonToList(items, ItemIdNumDTO.class);

        //构建商品信息
        List<CreateItemDTO> createItemDTOs = new ArrayList<CreateItemDTO>();
        if (itemIdNumDTOs != null && itemIdNumDTOs.size() > 0) {
            for (ItemIdNumDTO itemIdNumDTO : itemIdNumDTOs) {
                CreateItemDTO createItemDTO = new CreateItemDTO();
                createItemDTO.setItemId(itemIdNumDTO.getItemId());
                createItemDTO.setNum(itemIdNumDTO.getNum());
                createItemDTO.setPrice(price);
                createItemDTOs.add(createItemDTO);
            }
        }
        return createOrderByItemInfo(customer_id, src, terminal, deviceId, group_id, pay_type, address_id, "团购订单", 0, createItemDTOs);
    }

    /**
     * 拉新订单
     *
     * @param pay_type
     * @param items
     * @param address_id
     * @param orderCategory
     * @param shipfee
     * @return
     * @throws ServiceException
     */
    @Override
    public OrderStatusInfo newCustomerCreate(@ApiParameter(required = true, name = "pay_type", desc = "货到付款：COD，在线支付：ONLINE") String pay_type,
                                             @ApiParameter(required = true, name = "items", desc = "商品信息 [{\"itemId\":100893,\"num\":1,\"price\":10.00,}]") String items,
                                             @ApiParameter(required = true, name = "address_id", desc = "地址ID") int address_id,
                                             @ApiParameter(required = true, name = "orderCategory", desc = "订单类型") String orderCategory,
                                             @ApiParameter(required = true, name = "shipfee", desc = "运费") double shipfee) throws ServiceException {

        //【公共参数】
        //用户id
        String customer_id = RpcContext.getContext().getAttachment(CommonParameter.userId);
        //Terminal
        String terminal = RpcContext.getContext().getAttachment(ExtendParameter.terminal);
        //deviceId
        String deviceId = RpcContext.getContext().getAttachment(ExtendParameter.idfa);
        //src
        String src = RpcContext.getContext().getAttachment(ExtendParameter.src);

        //入参商品信息
        List<ItemIdNumDTO> itemIdNumDTOs = Json.jsonToList(items, ItemIdNumDTO.class);

        //构建商品信息
        List<CreateItemDTO> createItemDTOs = null;

        try {
            createItemDTOs = Json.jsonToList(items, CreateItemDTO.class);
        } catch (Exception ex) {
            logger.error("【创建订单|商品信息错误 in 创建订单方法】 报错");
            logger.error("【报错信息】 items=" + items);
            throw new ServiceException(OrderErrorCodes.errorCodes_GENERATER_ORDER_ERROR, "商品信息不正确");
        }
        return createOrderByItemInfo(customer_id, src, terminal, deviceId, 0, pay_type, address_id, orderCategory, shipfee, createItemDTOs);
    }

    /**
     * O2O 订单
     *
     * @param items
     * @return
     * @throws ServiceException
     */
    @Override
    public OrderStatusInfo OTOCreate(@ApiParameter(required = true, name = "items", desc = "商品信息 [{\"itemId\":100893,\"num\":1,\"price\":10.00,}]") String items) throws ServiceException {
        //【公共参数】
        //用户id
        String customer_id = RpcContext.getContext().getAttachment(CommonParameter.userId);
        //Terminal
        String terminal = RpcContext.getContext().getAttachment(ExtendParameter.terminal);
        //deviceId
        String deviceId = RpcContext.getContext().getAttachment(ExtendParameter.idfa);
        //src
        String src = RpcContext.getContext().getAttachment(ExtendParameter.src);

        //入参商品信息
        List<ItemIdNumDTO> itemIdNumDTOs = Json.jsonToList(items, ItemIdNumDTO.class);

        //构建商品信息
        List<CreateItemDTO> createItemDTOs = null;

        try {
            createItemDTOs = Json.jsonToList(items, CreateItemDTO.class);
        } catch (Exception ex) {
            logger.error("【创建订单|商品信息错误 in 创建订单方法】 报错");
            logger.error("【报错信息】 items=" + items);
            throw new ServiceException(OrderErrorCodes.errorCodes_GENERATER_ORDER_ERROR, "商品信息不正确");
        }

        //虚拟商品就算买多个，也拆成买1个多条记录
        List<CreateItemDTO> createItemDTOs_c = new ArrayList<CreateItemDTO>();
        if (createItemDTOs!=null&&createItemDTOs.size()>0)
        {
            for (CreateItemDTO createItemDTO:createItemDTOs)
            {
                for (int i =0;i<createItemDTO.getNum();i++)
                {
                    CreateItemDTO createItemDTO_c = new CreateItemDTO();
                    createItemDTO_c.setItemId(createItemDTO.getItemId());
                    createItemDTO_c.setNum(1);
                    createItemDTO_c.setPrice(createItemDTO.getPrice());
                    createItemDTOs_c.add(createItemDTO_c);
                }
            }
        }

        return createOrderByItemInfo(customer_id, src, terminal, deviceId, 0,"ONLINE", 0, "虚拟商品订单", 0, createItemDTOs_c);
    }

    /**
     * 订单信息获取及计算   【**此方法很重要， 结算页，计算价格接口，订单提交页都要用到】
     *
     * @param confirmInfo      订单数据对象
     * @param IsHasProduct     是否获取商品信息
     * @param IsHasPromo       是否获取优惠信息
     * @param IsHasCoupon      是否查询优惠券信息
     * @param SelfCouponId     自营优惠券ID
     * @param ProviderCouponId 直发优惠券ID
     * @param cartGetInfo      购物车对象
     * @throws ServiceException
     */
    private CalculationDTO calculationOrder(String customer_id, String terminal, ConfirmInfo confirmInfo, boolean IsHasProduct, boolean IsHasPromo, boolean IsHasCoupon, long SelfCouponId, long ProviderCouponId, CartGetInfo cartGetInfo) throws ServiceException {

        CalculationDTO calculationDTO = new CalculationDTO();
        //优惠券使用
        calculationDTO.setPromoDiscountList(new ArrayList<PromoDiscountInfo>());

        //循环购物车分组，构建信息
        for (GroupsDTO groupsDTO : cartGetInfo.getGroups()) {
            //公共参数
            double totalAmount =  0d;
            if(groupsDTO.getFee()!=null && groupsDTO.getFee().getActualTotal()>0.0){
                totalAmount=  groupsDTO.getFee().getActualTotal();
            }else{
                continue;
            }


            ItemGroupInfo itemGroupInfo = new ItemGroupInfo();

            //【分组其他信息】
            itemGroupInfo.setMode(groupsDTO.getMode());

            //【商品】
            if (IsHasProduct) {
                calculationProduct(groupsDTO, itemGroupInfo, cartGetInfo);
            }

            //【使用优惠】
            if (IsHasPromo) {
                calculationPromotions(groupsDTO, itemGroupInfo);
            }

            //【优惠券列表】
            if (IsHasCoupon) {
                //算运费
                Map<String, Double> shipfeeMap = getShipFee(itemGroupInfo.getMode(), groupsDTO.getFee().getActualTotal(), cartGetInfo.getCartWeight());
                //优惠券直传基础运费
                calculationCoupons(groupsDTO, itemGroupInfo, customer_id, terminal, shipfeeMap.get("SHIPFEE"));
            }

            //【金额计算】
            CalculationInfo calculation = new CalculationInfo();
            calculation.setSubAmount(getCartSubAmount(groupsDTO));    //商品总金额
            calculation.setPromotionDiscount(groupsDTO.getFee().getDiscount());    //商品优惠
            calculation.setShipFeeCouponDiscount(0);
            calculation.setTotalAmount(formatFloat(groupsDTO.getFee().getActualTotal()));

            //【拿优惠券信息】
            PromoInfo promoInfo = getpromotion(itemGroupInfo, SelfCouponId, ProviderCouponId, customer_id, terminal);

            //没有优惠券，直接计算
            if (promoInfo == null) {
                //算运费
                Map<String, Double> shipfeeMap = getShipFee(itemGroupInfo.getMode(), calculation.getTotalAmount(), cartGetInfo.getCartWeight());
                calculation.setShipFee(shipfeeMap.get("SHIPFEE") + shipfeeMap.get("OVERWEIGHT"));
                //是否超重
                itemGroupInfo.setOverweight(shipfeeMap.get("OVERWEIGHT").intValue() > 0);
                itemGroupInfo.setWeight(cartGetInfo.getCartWeight());
                //总金额=金额+运费
                calculation.setTotalAmount(formatFloat(calculation.getTotalAmount() + calculation.getShipFee()));
            } else {
                //获取优惠券减免详情
                PromoDiscount promoDiscount = promoDiscount(promoInfo.getId(), groupsDTO, itemGroupInfo, customer_id, terminal);

                //记录优惠券使用情况
                PromoDiscountInfo promoDiscountInfo = new PromoDiscountInfo();
                promoDiscountInfo.setPromoId(promoInfo.getId());
                promoDiscountInfo.setItems(promoDiscount.getItems());

                if (promoInfo.getType().equals("REDUCE")) {
                    //减金额
                    calculation.setProductCouponDiscount(formatFloat(promoDiscount.getCouponDiscount()));
                    calculation.setTotalAmount(formatFloat(calculation.getTotalAmount() - calculation.getProductCouponDiscount()));
                    //算运费
                    Map<String, Double> shipfeeMap = getShipFee(itemGroupInfo.getMode(), calculation.getTotalAmount(), cartGetInfo.getCartWeight());
                    calculation.setShipFee(shipfeeMap.get("SHIPFEE") + shipfeeMap.get("OVERWEIGHT"));
                    calculation.setTotalAmount(formatFloat(calculation.getTotalAmount() + calculation.getShipFee()));
                    //是否超重
                    itemGroupInfo.setOverweight(shipfeeMap.get("OVERWEIGHT").intValue() > 0);
                    itemGroupInfo.setWeight(cartGetInfo.getCartWeight());

                    //用券记录
                    promoDiscountInfo.setDiscount(calculation.getProductCouponDiscount());
                } else if (promoInfo.getType().equals("POSTAGEREDUCE")) {
                    //算运费
                    Map<String, Double> shipfeeMap = getShipFee(itemGroupInfo.getMode(), calculation.getTotalAmount(), cartGetInfo.getCartWeight());
                    calculation.setShipFee(shipfeeMap.get("SHIPFEE") + shipfeeMap.get("OVERWEIGHT"));
                    calculation.setTotalAmount(formatFloat(calculation.getTotalAmount() + calculation.getShipFee()));
                    //是否超重 重量
                    itemGroupInfo.setOverweight(shipfeeMap.get("OVERWEIGHT").intValue() > 0);
                    itemGroupInfo.setWeight(cartGetInfo.getCartWeight());
                    //减金额
                    double shipfeeDiscount = (promoDiscount.getShipFeeDiscount() - shipfeeMap.get("SHIPFEE")) > 0 ? shipfeeMap.get("SHIPFEE") : promoDiscount.getShipFeeDiscount();
                    calculation.setShipFeeCouponDiscount(formatFloat(shipfeeDiscount));
                    calculation.setTotalAmount(formatFloat(calculation.getTotalAmount() - calculation.getShipFeeCouponDiscount()));

                    //用券记录
                    promoDiscountInfo.setDiscount(shipfeeDiscount);
                }

                //用券记录
                calculationDTO.getPromoDiscountList().add(promoDiscountInfo);
            }

            itemGroupInfo.setCalculation(calculation);

            if (confirmInfo.getGroups() == null) {
                confirmInfo.setGroups(new ArrayList<>());
            }
            confirmInfo.getGroups().add(itemGroupInfo);
        }

        //订单金额
        CalculationInfo calculationInfo = new CalculationInfo();

        double subAmount = 0;
        double PromotionDiscount = 0;
        double shipFeeDiscount = 0;
        double productCouponDiscount = 0;
        double shipFeeCouponDiscount = 0;
        double shipFee = 0;

        double totalAmount = 0; //总金额
        if (confirmInfo.getGroups() != null) {
            for (ItemGroupInfo itemGroupInfo : confirmInfo.getGroups()) {
                totalAmount += itemGroupInfo.getCalculation().getTotalAmount();
                productCouponDiscount += itemGroupInfo.getCalculation().getProductCouponDiscount();
                shipFeeCouponDiscount += itemGroupInfo.getCalculation().getShipFeeCouponDiscount();
                PromotionDiscount += itemGroupInfo.getCalculation().getPromotionDiscount();
                shipFee += itemGroupInfo.getCalculation().getShipFee();
                subAmount += formatFloat(itemGroupInfo.getCalculation().getSubAmount());
            }
        }
        calculationInfo.setSubAmount(formatFloat(subAmount));
        calculationInfo.setPromotionDiscount(formatFloat((PromotionDiscount)));//商品优惠
        calculationInfo.setProductCouponDiscount(formatFloat(productCouponDiscount));
        calculationInfo.setShipFee(formatFloat(shipFee));
        calculationInfo.setShipFeeDiscount(shipFeeDiscount);
        calculationInfo.setShipFeeCouponDiscount(shipFeeCouponDiscount);
        calculationInfo.setTotalAmount(formatFloat((totalAmount))); //商品总金额
        confirmInfo.setCalculation(calculationInfo);

        return calculationDTO;
    }

    /**
     * 获取单个优惠券信息
     *
     * @param itemGroupInfo
     * @param SelfCouponId
     * @param ProviderCouponId
     * @param customer_id
     * @param terminal
     * @return
     * @throws ServiceException
     */
    private PromoInfo getpromotion(ItemGroupInfo itemGroupInfo, long SelfCouponId, long ProviderCouponId, String customer_id, String terminal) throws ServiceException {
        PromoInfo promoInfo = null;

        long CouponId = 0;
        if (itemGroupInfo.getCouponGroups() != null && itemGroupInfo.getCouponGroups().size() > 0) {
            for (CouponGroupInfo couponGroupInfo : itemGroupInfo.getCouponGroups()) {
                if (couponGroupInfo.getGroupName().equals("USABLE")) {
                    if (couponGroupInfo.getCoupons() != null && couponGroupInfo.getCoupons().size() > 0) {
                        boolean isDefault = false;
                        for(CouponInfo couponInfo:couponGroupInfo.getCoupons()){
                            if (itemGroupInfo.getMode().equals("自营") && SelfCouponId != 0) {
                                if(couponInfo.getId()==SelfCouponId){
                                    CouponId = SelfCouponId;
                                    isDefault = true;
                                    couponInfo.setDefault(true);
                                }
                            }
                            if ((itemGroupInfo.getMode().equals("直发") && ProviderCouponId != 0)) {
                                if(couponInfo.getId()==ProviderCouponId){
                                    CouponId = ProviderCouponId;
                                    isDefault = true;
                                    couponInfo.setDefault(true);
                                }
                            }
                        }




                        CouponId = couponGroupInfo.getCoupons().get(0).getId();
                        if(!isDefault){
                            couponGroupInfo.getCoupons().get(0).setDefault(true);
                        }

                    }
                }
            }
        }

        if (itemGroupInfo.getCouponGroupsNew() != null && itemGroupInfo.getCouponGroupsNew().size() > 0) {
            for (CouponGroupInfoNew couponGroupInfoNew : itemGroupInfo.getCouponGroupsNew()) {
                if (couponGroupInfoNew.getGroupName().equals("USABLE")) {
                    if (couponGroupInfoNew.getCoupons() != null && couponGroupInfoNew.getCoupons().size() > 0) {
                        boolean isDefault = false;
                        for(ProInfo couponInfo:couponGroupInfoNew.getCoupons()){
                            if (itemGroupInfo.getMode().equals("自营") && SelfCouponId != 0) {
                                if(couponInfo.getId()==SelfCouponId){
                                    CouponId = SelfCouponId;
                                    isDefault = true;
                                    couponInfo.setDefault(true);
                                }
                            }
                            if ((itemGroupInfo.getMode().equals("直发") && ProviderCouponId != 0)) {
                                if(couponInfo.getId()==ProviderCouponId){
                                    CouponId = ProviderCouponId;
                                    isDefault = true;
                                    couponInfo.setDefault(true);
                                }
                            }
                        }

                        if(!isDefault){
                            couponGroupInfoNew.getCoupons().get(0).setDefault(true);
                        }

                    }
                }
            }
        }



        if (CouponId == 0) {
            if (itemGroupInfo.getMode().equals("自营") && SelfCouponId != 0) {
                CouponId = SelfCouponId;
            }
            if ((itemGroupInfo.getMode().equals("直发") && ProviderCouponId != 0)) {
                CouponId = ProviderCouponId;
            }
        }

        if (CouponId != 0) {
            RpcContext.getContext().setAttachment(CommonParameter.userId, customer_id);
            RpcContext.getContext().setAttachment(ExtendParameter.terminal, terminal);
            try {
                logger.info("[优惠券服务|获取优惠券信息] CouponId=" + CouponId);
                promoInfo = promoService.getPromoById(CouponId);
                logger.info("[优惠券服务|获取优惠券信息] promoInfo=" + Json.toJson(promoInfo));
            } catch (Exception ex) {
                logger.warn("【优惠券服务|获取优惠券信息】（失败）");
                logger.error(ex);
                throw new ServiceException(OrderErrorCodes.errorCodes_COUPONCALCULATE_NOT_FOUND, "【优惠券服务|获取优惠券信息】（失败）");
            }
        }
        return promoInfo;
    }

    /**
     * 计算运费
     *
     * @param totalAmout
     * @param weight
     * @return
     */
    private Map<String, Double> getShipFee(String mode, double totalAmout, double weight) {
        Map<String, Double> rtn = new HashMap<String, Double>();

        Double shipFee = 0.00d;
        Double overWeight = 0.00d;

        if (mode.equals("直发")) {
            rtn.put("SHIPFEE", shipFee);
            rtn.put("OVERWEIGHT", overWeight);
            return rtn;
        }

        if (new Double(totalAmout * 100).intValue() > (98.99999 * 100)) {
            if (new Double(weight).intValue() < new Double((totalAmout + 1) / 100).intValue() * 10000) {
                //包邮
            } else {
                //超重
                overWeight = new Double(
                        new Double(weight / 1000).intValue() + ((weight % 1000) > 0 ? 1 : 0)
                                - new Double((totalAmout + 1) / 100).intValue() * 10
                );

                //overWeight= new Double(weiKg%10);
                //formatFloat(new Double(((weight - ((new Double((totalAmout+1)/100).intValue()*10-1)*1000+1)) / 1000)).intValue());
            }
        } else {
            if (new Double(weight).intValue() < 5000) {
                //运费15
                shipFee = 15.00d;
            } else {
                //运费15
                shipFee = 15.00d;
                overWeight =
                        formatFloat(new Double((weight - 5000.00) / 1000).intValue())  //超出运费
                                + (((weight - 5000) % 1000) > 0 ? 1 : 0); //不满1kg 按1kg算
            }
        }
        rtn.put("SHIPFEE", shipFee);
        rtn.put("OVERWEIGHT", overWeight);
        return rtn;
    }

    /**
     * calculationProduct
     *
     * @param groupsDTO
     * @param itemGroupInfo
     */
    private void calculationProduct(GroupsDTO groupsDTO, ItemGroupInfo itemGroupInfo, CartGetInfo cartGetInfo) throws ServiceException {
        try {

            //【分组的商品】
            List<ItemInfo> items = new ArrayList<ItemInfo>();

            //【解析购物车商品】
            //专区商品
            List<CombineDTO> combineDTOs = groupsDTO.combine;
            if (combineDTOs != null && combineDTOs.size() > 0) {
                for (CombineDTO combineDTO : combineDTOs) {
                    List<ItemsDTO> itemsDTOs = combineDTO.getItems();
                    items.addAll(ItemCartMapping(itemsDTOs, false));

                    //获取专区单个商品赠品
                    for (ItemsDTO itemsDTO : itemsDTOs) {
                        List<PromotionsDTO> promotionsDTOs = itemsDTO.getPromotions();
                        if (promotionsDTOs != null && promotionsDTOs.size() > 0) {
                            for (PromotionsDTO promotionsDTO : promotionsDTOs) {
                                List<ItemsDTO> giftitems = promotionsDTO.getGiftItem();
                                if (giftitems != null && giftitems.size() > 0) {
                                    items.addAll(ItemCartMapping(giftitems, true));
                                }
                            }
                        }
                    }
                }
            }

            //获取专区赠品
            if (combineDTOs != null && combineDTOs.size() > 0) {
                for (CombineDTO combineDTO : combineDTOs) {

                    List<PromotionsDTO> promotionsDTOs = combineDTO.getPromotions();
                    //获取专区单个商品赠品
                    if (promotionsDTOs != null && promotionsDTOs.size() > 0) {
                        for (PromotionsDTO promotionsDTO : promotionsDTOs) {
                            List<ItemsDTO> giftitems = promotionsDTO.getGiftItem();
                            if (giftitems != null && giftitems.size() > 0) {
                                items.addAll(ItemCartMapping(giftitems, true));
                            }
                        }
                    }
                }
            }

            //单个商品
            if (groupsDTO.getSingle() != null && groupsDTO.getSingle().size() > 0) {
                items.addAll(ItemCartMapping(groupsDTO.getSingle(), false));
            }
            //获取单个商品赠品
            for (ItemsDTO itemsDTO : groupsDTO.getSingle()) {
                List<PromotionsDTO> promotionsDTOs = itemsDTO.getPromotions();
                if (promotionsDTOs != null && promotionsDTOs.size() > 0) {
                    for (PromotionsDTO promotionsDTO : promotionsDTOs) {
                        List<ItemsDTO> giftitems = promotionsDTO.getGiftItem();
                        if (giftitems != null && giftitems.size() > 0) {
                            items.addAll(ItemCartMapping(giftitems, true));
                        }
                    }
                }
            }
            itemGroupInfo.setItems(items);

            //【商品个数统计】
            int itemCount = 0;
            int giftCount = 0;
            for (ItemInfo itemInfo : items) {
                if (itemInfo.getIsGift()) {
                    giftCount += itemInfo.getQuantity();
                } else {
                    itemCount += itemInfo.getQuantity();
                }
            }
            //赠品个数
            itemGroupInfo.setGiftCount(giftCount);
            //商品个数
            itemGroupInfo.setItemCount(itemCount);

            //重量，是否超重  判断逻辑拿到计算运费那里
            /*if (cartGetInfo!=null)
            {
                itemGroupInfo.setWeight(cartGetInfo.getCartWeight());
                if (cartGetInfo.getFee()!=null&&cartGetInfo.getFee().getPostage()!=null&&cartGetInfo.getFee().getPostage().size()>0)
                {
                    ReducesDTO reducesDTO = cartGetInfo.getFee().getPostage().get(0);
                    if (reducesDTO!=null)
                    {
                        //ID大于0  且金额不为0 就是超重
                        itemGroupInfo.setOverweight(reducesDTO.getId()>0&&reducesDTO.getReducePrice()>0);
                    }
                }
            }*/

            //下面是结算页要按照购物车显示。直接搬购物车原型
            CartGroupsDTO cartGroupsDTO = new CartGroupsDTO();
            List<CartPromotionsDTO> cartPromotionsDTOs = new ArrayList<CartPromotionsDTO>();
            dozerBeanMapper.map(groupsDTO.getPromotions(), cartPromotionsDTOs);
            cartGroupsDTO.setPromotions(cartPromotionsDTOs);

            List<CartCombineDTO> cartCombineDTOs = new ArrayList<CartCombineDTO>();
            dozerBeanMapper.map(groupsDTO.getCombine(), cartCombineDTOs);
            cartGroupsDTO.setCombine(cartCombineDTOs);

            List<CartItemsDTO> cartItemsDTOs = new ArrayList<CartItemsDTO>();
            dozerBeanMapper.map(groupsDTO.getSingle(), cartItemsDTOs);
            cartGroupsDTO.setSingle(cartItemsDTOs);

            CartFeeDTO cartFeeDTO = new CartFeeDTO();
            dozerBeanMapper.map(groupsDTO.getFee(), cartFeeDTO);
            cartGroupsDTO.setFee(cartFeeDTO);

            itemGroupInfo.setCartGroupInfo(cartGroupsDTO);

        } catch (Exception ex) {
            logger.error("[解析商品 in 解析购物车商品方法] （报错）");
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_CALCULATIONPRODUCT_ERROR, "[解析商品 in 解析购物车商品方法] （失败）");
        }
    }

    /**
     * calculationPromotions
     *
     * @param groupsDTO
     * @param itemGroupInfo
     * @throws ServiceException
     */
    private void calculationPromotions(GroupsDTO groupsDTO, ItemGroupInfo itemGroupInfo) throws ServiceException {
        try {

            List<PromotionInfo> promotionInfos = new ArrayList<PromotionInfo>();

            //得到优惠与对应商品
            List<PromotionSplitDTO> promotionSplitDTOs = getPromotionSplitDto(groupsDTO);
            if (promotionSplitDTOs != null && promotionSplitDTOs.size() > 0) {
                for (PromotionSplitDTO promotionSplitDTO : promotionSplitDTOs) {
                    if (promotionSplitDTO.getType().equals("REDUCE")) {
                        PromotionInfo promotionInfo = new PromotionInfo();
                        promotionInfo.setId(promotionSplitDTO.getPromotionId());
                        promotionInfo.setDiscount(promotionSplitDTO.getAmount());
                        promotionInfo.setType(promotionSplitDTO.getType());
                        promotionInfos.add(promotionInfo);
                    }
                }
            }

            itemGroupInfo.setPromotions(promotionInfos);
        } catch (Exception ex) {
            logger.error("[解析优惠 in 解析购物车使用优惠] （报错）");
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_CALCULATIONPROMOTIONS_ERROR, "[解析优惠 in 解析购物车使用优惠] （报错）");
        }
    }

    /**
     * calculationCoupons
     *
     * @param itemGroupInfo
     * @param customer_id
     * @param terminal
     * @param totalAmount
     * @throws ServiceException
     */
    private void calculationCoupons(GroupsDTO groupsDTO, ItemGroupInfo itemGroupInfo, String customer_id, String terminal, double totalAmount) throws ServiceException {
        //**   totalAmount 以前是总金额，现在不该接口  直接当运费用

        //券类型  直发，自营
        String mode = groupsDTO.getMode().equals("自营") ? "SELF" : "consignation";

        //优惠服务调用商品信息
        String iteminfo = getPromotionItemStr(groupsDTO, itemGroupInfo);
        //可用优惠券
        List<ProInfo> true_CouponInfo = new ArrayList<ProInfo>();
        // 满减优惠券
        List<ProInfo> trueCouponInfoReduce = new ArrayList<ProInfo>();
        // 包邮优惠券
        List<ProInfo> trueCouponInfoPost = new ArrayList<ProInfo>();
        RpcContext.getContext().setAttachment(CommonParameter.userId, customer_id);
        RpcContext.getContext().setAttachment(ExtendParameter.terminal, terminal);
        List<PromoInfo> true_promoInfos = null;
        try {
            logger.info("[优惠券服务|获取可用优惠券列表] totalAmount=" + totalAmount + " iteminfo=" + iteminfo);
            true_promoInfos = promoService.getListNew(1, totalAmount, iteminfo, mode);
            logger.info("[优惠券服务|可用优惠券结果] promoInfos=" + Json.toJson(true_promoInfos));
        } catch (Exception ex) {
            logger.error("【优惠券服务|获取可用优惠券列表】（报错）");
            logger.error("报错信息：iteminfo=" + iteminfo);
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_COUPONLIST_NOT_FOUND, "【优惠券服务|获取优惠券列表】（报错）");
        }

        if (true_promoInfos != null) {
            if (true_promoInfos != null) {
                for (PromoInfo promoInfo : true_promoInfos) {

                    ProInfo proInfo = new ProInfo();
                    proInfo.setId(promoInfo.getId());
                    proInfo.setType(promoInfo.getType());
                    proInfo.setDesc(promoInfo.getDesc());
                    proInfo.setTitle(promoInfo.getTitle());
                    proInfo.setStart(promoInfo.getStart());
                    proInfo.setEnd(promoInfo.getEnd());
                    proInfo.setPcUrl(promoInfo.getPcUrl());
                    proInfo.setMobileUrl(promoInfo.getMobileUrl());
                    proInfo.setProductFrom(promoInfo.getProductFrom());
                    proInfo.setTerminal(promoInfo.getTerminal());
                    proInfo.setStatus(promoInfo.getStatus());
                    proInfo.setShop(promoInfo.getShop()); //oto
                    proInfo.setTip(promoInfo.getTip());
                    proInfo.setItems(promoInfo.getItems());
                    proInfo.setAmounts(promoInfo.getAmounts());
                    proInfo.setDifference(promoInfo.getDifference());
//                    proInfo.setCreatetime(promoInfo.getCreatetime());
                    PromoRules promoRules = promoInfo.getRules();
                    if (promoRules != null) {
                        ProRules rules = new ProRules();
                        rules.setId(promoRules.getId());
                        rules.setLimit(promoRules.getLimit());
                        rules.setPreferential(promoRules.getPreferential());
                        rules.setDesc(promoRules.getDesc());
                        proInfo.setRules(rules);
                    }

                  //  true_CouponInfo.add(proInfo);
                    if(promoInfo.getType().equals("REDUCE")){
                        trueCouponInfoReduce.add(proInfo);
                    }else if(promoInfo.getType().equals("POSTAGEREDUCE")){
                        trueCouponInfoPost.add(proInfo);
                    }
                }
            }
            sortCoupon(trueCouponInfoReduce);
            sortCouponPost(trueCouponInfoPost);
            true_CouponInfo.addAll(trueCouponInfoReduce);
            true_CouponInfo.addAll(trueCouponInfoPost);
            //dozerBeanMapper.map(true_promoInfos,true_CouponInfo);
            // 按金额倒序
//            Collections.sort(true_CouponInfo, new Comparator<ProInfo>() {
//                public int compare(ProInfo arg0, ProInfo arg1) {
//                    double hits0 = arg0.getRules().getPreferential();
//                    double hits1 = arg1.getRules().getPreferential();
//                    if (hits1 > hits0) {
//                        return 1;
//                    } else if (hits1 == hits0) {
//                        return 0;
//                    } else {
//                        return -1;
//                    }
//                }
//            });
        }

        //可用优惠券整理
        CouponGroupInfoNew true_couponGroupinfo = new CouponGroupInfoNew();
        true_couponGroupinfo.setGroupName("USABLE");
        true_couponGroupinfo.setCoupons(true_CouponInfo);

        //不可用优惠券
        List<ProInfo> false_CouponInfo = new ArrayList<ProInfo>();
        RpcContext.getContext().setAttachment(CommonParameter.userId, customer_id);
        RpcContext.getContext().setAttachment(ExtendParameter.terminal, terminal);
        List<PromoInfo> false_promoInfos = null;
        try {
            false_promoInfos = promoService.getListNew(2, totalAmount, iteminfo, mode);
        } catch (Exception ex) {
            logger.error("【优惠券服务|获取不可用优惠券列表】（报错）");
            logger.error("报错信息：iteminfo=" + iteminfo);
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_COUPONLIST_NOT_FOUND, "【优惠券服务|获取优惠券列表】（报错）");
        }

        if (false_promoInfos != null) {
            for (PromoInfo promoInfo : false_promoInfos) {
                ProInfo proInfo = new ProInfo();
                proInfo.setId(promoInfo.getId());
                proInfo.setType(promoInfo.getType());
                proInfo.setDesc(promoInfo.getDesc());
                proInfo.setTitle(promoInfo.getTitle());
                proInfo.setStart(promoInfo.getStart());
                proInfo.setEnd(promoInfo.getEnd());
                proInfo.setPcUrl(promoInfo.getPcUrl());
                proInfo.setMobileUrl(promoInfo.getMobileUrl());
                proInfo.setProductFrom(promoInfo.getProductFrom());
                proInfo.setTerminal(promoInfo.getTerminal());
                proInfo.setStatus(promoInfo.getStatus());
                proInfo.setShop(promoInfo.getShop()); //oto
                proInfo.setTip(promoInfo.getTip());
                proInfo.setItems(promoInfo.getItems());
                proInfo.setAmounts(promoInfo.getAmounts());
                proInfo.setDifference(promoInfo.getDifference());
//                proInfo.setCreatetime(promoInfo.getCreatetime());

                PromoRules promoRules = promoInfo.getRules();
                if (promoRules != null) {
                    ProRules rules = new ProRules();
                    rules.setId(promoRules.getId());
                    rules.setLimit(promoRules.getLimit());
                    rules.setPreferential(promoRules.getPreferential());
                    rules.setDesc(promoRules.getDesc());
                    proInfo.setRules(rules);
                }
                false_CouponInfo.add(proInfo);
            }
        }

        //不可用优惠券整理
        CouponGroupInfoNew false_couponGroupinfo = new CouponGroupInfoNew();
        false_couponGroupinfo.setGroupName("DISABLE");
        false_couponGroupinfo.setCoupons(false_CouponInfo);

        //优惠券列表加入到返回结果中
        itemGroupInfo.setCouponGroupsNew(new ArrayList<CouponGroupInfoNew>());
        itemGroupInfo.getCouponGroupsNew().add(true_couponGroupinfo);
        itemGroupInfo.getCouponGroupsNew().add(false_couponGroupinfo);


        //兼容老的优惠券列表
        itemGroupInfo.setCouponGroups(new ArrayList<CouponGroupInfo>());
        //循环遍历新的券，去赋值到老的券
        if (itemGroupInfo.getCouponGroupsNew() != null && itemGroupInfo.getCouponGroupsNew().size() > 0) {
            List<CouponGroupInfoNew> couponGroupInfoNews = itemGroupInfo.getCouponGroupsNew();
            for (CouponGroupInfoNew couponGroupInfoNew : couponGroupInfoNews) {
                CouponGroupInfo couponGroupInfo = new CouponGroupInfo();
                couponGroupInfo.setGroupName(couponGroupInfoNew.getGroupName());
                couponGroupInfo.setCoupons(new ArrayList<CouponInfo>());

                List<ProInfo> proInfos = couponGroupInfoNew.getCoupons();
                if (proInfos != null && proInfos.size() > 0) {
                    for (ProInfo proInfo : proInfos) {
                        CouponInfo couponInfo = new CouponInfo();
                        couponInfo.setId(proInfo.getId());
                        couponInfo.setType(proInfo.getType());
                        couponInfo.setDesc(proInfo.getDesc());
                        couponInfo.setTitle(proInfo.getTitle());
                        couponInfo.setStart(proInfo.getStart());
                        couponInfo.setEnd(proInfo.getEnd());

                        ProRules proRules = proInfo.getRules();
                        if (proRules != null) {
                            couponInfo.setLimit(proRules.getLimit());
                            couponInfo.setPreferential(proRules.getPreferential());
                            couponInfo.setRulesDesc(proRules.getDesc());
                        }

                        couponGroupInfo.getCoupons().add(couponInfo);
                    }
                }
                itemGroupInfo.getCouponGroups().add(couponGroupInfo);
            }
        }

    }

    /**
     * 调用优惠券str
     *
     * @param groupsDTO
     * @param itemGroupInfo
     * @return
     */
    private String getPromotionItemStr(GroupsDTO groupsDTO, ItemGroupInfo itemGroupInfo) {
        String rtn = "";

        //使用的优惠
        List<PromotionSplitDTO> promotionSplitDTOs = getPromotionSplitDto(groupsDTO);

       /*
        1   REDUCE	满额减，满199减50，满299减70等
        2   GIVE	满额送，满199送澳洲大青龙，满299送西班牙美女等
        3	PIECEREDUCE	满件减，购买澳洲牛骨2份减80元
        4	PIECEGIVE	满件送，购买西冷牛排3份送苏泊尔牛排锅
        5	OPTIONALLY	N元M件，99元专区任选3件，199元专区任选4件等
        6	SPECIAL	限时特价
        7	FIRSTREDUCE	首单满额减，用户首次下单，订单金额满99减30元
        8	FIRSTGIVE*/

        //先组织要排除的商品
        Map<String, String> notItemMap = new HashMap<String, String>();

        if (promotionSplitDTOs != null && promotionSplitDTOs.size() > 0) {
            for (PromotionSplitDTO promotionSplitDTO : promotionSplitDTOs) {
                if (promotionSplitDTO.getPromotionType().equals("REDUCE")
                        || promotionSplitDTO.getPromotionType().equals("PIECEREDUCE")
                        || promotionSplitDTO.getPromotionType().equals("OPTIONALLY")) {
                    List<ItemsDTO> itemsDTOs = promotionSplitDTO.getItemsDTOs();
                    if (itemsDTOs != null && itemsDTOs.size() > 0) {
                        for (ItemsDTO itemsDTO : itemsDTOs) {
                            if (!notItemMap.containsKey(String.valueOf(itemsDTO.getId()))) {
                                notItemMap.put(String.valueOf(itemsDTO.getId()), String.valueOf(itemsDTO.getId()));
                            }
                        }
                    }
                }
            }
        }

        //构建可用优惠券商品
        List<PromotionItemDTO> promotionItemDTOs = new ArrayList<PromotionItemDTO>();
        for (ItemInfo itemInfo : itemGroupInfo.getItems()) {
            if (!notItemMap.containsKey(String.valueOf(itemInfo.getItemId())) && itemInfo.getIsGift() == false) {
                PromotionItemDTO promotionItemDTO = new PromotionItemDTO();
                promotionItemDTO.setItemId(itemInfo.getItemId());
                promotionItemDTO.setNum(itemInfo.getQuantity());
                promotionItemDTO.setPrice(itemInfo.getUnitPrice());
                promotionItemDTOs.add(promotionItemDTO);
            }
        }
        rtn = Json.toJson(promotionItemDTOs);
        return rtn;
    }

    /**
     * promoDiscount
     *
     * @param itemGroupInfo
     * @param customer_id
     * @param terminal
     * @return
     * @throws ServiceException
     */
    private PromoDiscount promoDiscount(long promoId, GroupsDTO groupsDTO, ItemGroupInfo itemGroupInfo, String customer_id, String terminal) throws ServiceException {
        //调用商品服务商品string
        PromoDiscount promoDiscount = null;
        if (promoId != 0) {
            //查优惠券   商品构建
            List<ItemIdNumDTO> itemIdNums = new ArrayList<ItemIdNumDTO>();
            for (ItemInfo itemInfo : itemGroupInfo.getItems()) {
                ItemIdNumDTO itemIdNum = new ItemIdNumDTO();
                itemIdNum.setItemId(itemInfo.getItemId());
                itemIdNums.add(itemIdNum);
            }
            String iteminfo = getPromotionItemStr(groupsDTO, itemGroupInfo);
            RpcContext.getContext().setAttachment(CommonParameter.userId, customer_id);
            RpcContext.getContext().setAttachment(ExtendParameter.terminal, terminal);
            try {
                logger.info("[优惠券服务|计算优惠券参数] CouponId=" + promoId + " iteminfo" + iteminfo);
                promoDiscount = promoService.calculate(promoId, 0, 0, iteminfo);
                logger.info("[优惠券服务|计算优惠券结果] promoDiscount=" + Json.toJson(promoDiscount));
            } catch (Exception ex) {
                logger.warn("【优惠券服务|计算优惠券】（失败）");
                logger.error(ex);
                throw new ServiceException(OrderErrorCodes.errorCodes_COUPONCALCULATE_NOT_FOUND, "【优惠券服务|计算优惠券】（失败）");
            }
        }
        return promoDiscount;
    }

    /**
     * getCartSubAmount
     *
     * @param groupsDTO
     * @return
     * @throws ServiceException
     */
    private double getCartSubAmount(GroupsDTO groupsDTO) throws ServiceException {
        //商品总金额
        double SubAmount = 0.00;
        //【分组的商品】
        List<ItemInfo> items = new ArrayList<ItemInfo>();
        //专区商品
        List<CombineDTO> combineDTOs = groupsDTO.combine;
        for (CombineDTO combineDTO : combineDTOs) {
            List<ItemsDTO> itemsDTOs = combineDTO.getItems();
            if (itemsDTOs != null && itemsDTOs.size() > 0) {
                for (ItemsDTO itemsDTO : itemsDTOs) {
                    SubAmount += formatFloat(itemsDTO.getRetailPrice() * itemsDTO.getNum());
                }
            }
        }
        //单个商品
        List<ItemsDTO> itemsDTOs = groupsDTO.getSingle();
        if (itemsDTOs != null && itemsDTOs.size() > 0) {
            for (ItemsDTO itemsDTO : itemsDTOs) {
                SubAmount += formatFloat(itemsDTO.getRetailPrice() * itemsDTO.getNum());
            }
        }
        return SubAmount;
    }

    /**
     * 购物车itemmapping
     *
     * @param itemsDTOs
     * @param isGift
     * @return
     */
    private List<ItemInfo> ItemCartMapping(List<ItemsDTO> itemsDTOs, boolean isGift) {
        List<ItemInfo> list = new ArrayList<ItemInfo>();
        if (itemsDTOs != null && itemsDTOs.size() > 0) {
            for (ItemsDTO itemsDTO : itemsDTOs) {
                ItemInfo itemInfo = new ItemInfo();
                itemInfo.setUnitPrice(itemsDTO.getRetailPrice());
                itemInfo.setImgUrl((itemsDTO.getImages() != null && itemsDTO.getImages().size() >= 0) ? itemsDTO.getImages().get(0) : "");
                itemInfo.setItemTitle(itemsDTO.getTitle());
                itemInfo.setItemId(itemsDTO.getId());
                itemInfo.setQuantity(itemsDTO.getNum());
                itemInfo.setIsGift(isGift);
                itemInfo.setTags(itemsDTO.getTags());
                list.add(itemInfo);
            }
        }
        return list;
    }

    /**
     * 创建订单
     *
     * @param customer_id       用户ID
     * @param address_id        地址ID
     * @param saleOrder         主订单信息
     * @param saleOrderItemList 订单上商品信息
     * @param cartGetInfo       购物车信息（拆分优惠使用）
     * @throws ServiceException
     */
    private OrderStatusInfo createOrder(String deviceId, String customer_id, long address_id, SaleOrder saleOrder, List<SaleOrderItem> saleOrderItemList
            , CartGetInfo cartGetInfo, CalculationDTO calculationDTO,Map<String,String> map) throws ServiceException {

        //【公共参数】
        //亿起发跟踪信息
        //emar_source
        String emar_source = map.containsKey(ExtendParameter.emar_source)?map.get(ExtendParameter.emar_source):"";
        logger.info("emar_source = " + emar_source == null ? "null" : emar_source);
        //emar_channel
        String emar_channel = map.containsKey(ExtendParameter.emar_channel)?map.get(ExtendParameter.emar_channel):"";
        logger.info("emar_channel = " + emar_channel == null ? "null" : emar_channel);
        //emar_cid
        String emar_cid = map.containsKey(ExtendParameter.emar_cid)?map.get(ExtendParameter.emar_cid):"";
        logger.info("emar_cid = " + emar_cid == null ? "null" : emar_cid);
        //emar_wi
        String emar_wi =map.containsKey(ExtendParameter.emar_wi)?map.get(ExtendParameter.emar_wi):"";
        logger.info("emar_wi = " + emar_wi == null ? "null" : emar_wi);

        String source = (emar_source == null || emar_source.isEmpty()) ? "" : emar_source + "|" + emar_cid;
        if ((saleOrder.getSource() == null || saleOrder.getSource().isEmpty())) saleOrder.setSource(source);

        //当前时间
        Date now = new Date();
        OrderStatusInfo orderInfo = new OrderStatusInfo();

        //检查商品数量是否为0
        if (saleOrderItemList != null && saleOrderItemList.size() > 0) {
            for (SaleOrderItem saleOrderItem : saleOrderItemList) {
                if (saleOrderItem.getQuantity() == 0) {
                    logger.error("【创建订单|商品数量为0 in 创建订单方法】 报错");
                    logger.error("【报错信息】 itemId=" + saleOrderItem.getItemId() + "  so_no" + saleOrder.getSaleNo());
                    throw new ServiceException(OrderErrorCodes.errorCodes_GENERATER_ORDER_ERROR, "商品 【" + saleOrderItem.getItemTitle() + "】 数量为0");
                }
            }
        }

        //校验常用参数  是否直发
        boolean hasZhiFa = false;
        if (saleOrder.getOrderCategory().equals("普通订单")) {
            List<GroupsDTO> groupsDTOs = cartGetInfo.getGroups();
            for (GroupsDTO groupsDTO : groupsDTOs) {
                if (groupsDTO.getMode().equals("直发")) {
                    hasZhiFa = true;
                    break;
                }
            }
        }

        //【查询地址】
        RpcContext.getContext().setAttachment(CommonParameter.userId, customer_id);
        List<CustomerAddressInfo> customerAddressInfos = null;

        if (!saleOrder.getOrderCategory().equals("虚拟商品订单")) //虚拟订单没有地址
        {
            try {
                customerAddressInfos = memberService.addressList(address_id);
            } catch (Exception ex) {
                logger.error("【会员服务|获取用户地址 in 创建订单方法】 报错");
                logger.error("【报错信息】 address_id=" + address_id);
                logger.error(ex);
                throw new ServiceException(OrderErrorCodes.errorCodes_ADDRESSLIST_NOT_FOUND, "【会员服务|获取用户地址 in 创建订单方法】 报错 exMsg=" + ex.getMessage());
            }
            if (customerAddressInfos == null || customerAddressInfos.size() == 0) {
                logger.error("【会员服务|获取用户地址 in 创建订单方法】 结果异常");
                logger.error("【报错信息】 没查到对应地址 address_id=" + address_id);
                throw new ServiceException(OrderErrorCodes.errorCodes_ADDRESSLIST_NOT_FOUND, "【会员服务|获取用户地址 in 创建订单方法】 结果异常,没查到用户地址 address_id=" + address_id);
            }
        }


        //【校验配送日期】
        if (saleOrder.getOrderCategory().equals("普通订单")) {
            if (saleOrder.getShipDate().getTime() != 0) {
                StringBuffer sbfItem = new StringBuffer();
                for (SaleOrderItem saleOrderItem : saleOrderItemList) {
                    if (sbfItem.length() != 0) {
                        sbfItem.append(",");
                    }
                    sbfItem.append(saleOrderItem.getItemId());
                }
                boolean checkDelivery = checkDeliveryDatebyProduct(customerAddressInfos.get(0).getCityZoneId(), sbfItem.toString(), saleOrder.getShipDate().getTime());
                if (!checkDelivery) {
                    throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_DELIVERYDATES_ERROR, "日期不可配送");
                }
            }
            else if (saleOrder.getShipDate().getTime() == 0) {
                //如果是自营 不正确
                if (cartGetInfo != null && cartGetInfo.getGroups() != null && cartGetInfo.getGroups().size() > 0) {
                    if (!hasZhiFa) {
                        throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_DELIVERYDATES_ERROR, "请选择配送日期");
                    } else {
                        //订单只是独立直发，这里先给个时间保证数据完整性，之后会在订单同步时重新计算配送时间
                         /* http://120.55.164.190:8080/browse/DEV-192
                            目的：为了满足运营的提出的截单时间的调整。以及防止漏单现象，特此把截单取订单时间，改为支付时间。
                            供应商直发商品（OM系统中）配送时间调整如下：
                            配送时间=支付时间（12点之前）+2天
                                配送时间=支付时间（12点之后）+3天*/
                        Calendar instance = Calendar.getInstance();
                        if (instance.get(Calendar.HOUR_OF_DAY) >= 12) {
                            instance.add(Calendar.DATE, 3);
                        } else {
                            instance.add(Calendar.DATE, 2);
                        }
                        saleOrder.setShipDate(instance.getTime());
                    }
                }
            }
        } else if (saleOrder.getOrderCategory().equals("团购订单")|| saleOrder.getOrderCategory().equals("市场部拉新订单")) {
            //配送时间校验
            //团购订单的配送时间
            //团购订单，20：30点前成团，配送日期T+1，20：30点后配送日期T+2
            Calendar instance = Calendar.getInstance();
            if (instance.get(Calendar.HOUR_OF_DAY) > 20 || (instance.get(Calendar.HOUR_OF_DAY) == 20 && instance.get(Calendar.MINUTE) >= 30)) {
                instance.add(Calendar.DATE, 2);
            } else {
                instance.add(Calendar.DATE, 1);
            }
            saleOrder.setShipDate(instance.getTime());
        } else if (saleOrder.getOrderCategory().equals("虚拟商品订单"))
        {
            //虚拟商品订单不校验配送日期
        }
        else
        {
            logger.warn("[下单配送日期校验日志] 没匹配到订单类型 info=" +Json.toJson(saleOrder));
        }

        //支付方式校验
        boolean checkPaytype = false;

        long cityZoneId = saleOrder.getOrderCategory().equals("虚拟商品订单") ? 0 : customerAddressInfos.get(0).getCityZoneId();

        List<PayTypeInfo> payTypeInfos = confirmPayTyps(hasZhiFa, cityZoneId); //获取支付方式
        if (payTypeInfos != null && payTypeInfos.size() > 0) {
            for (PayTypeInfo payTypeInfo : payTypeInfos) {
                if (saleOrder.getPayType().equals(payTypeInfo.getName())) {
                    checkPaytype = true;
                    break;
                }
            }
        }
        if (!checkPaytype) {
            throw new ServiceException(OrderErrorCodes.errorCodes_GENERATER_ORDER_ERROR, "支付方式不可用");
        }

        //构建订单配送信息
        SaleOrderShip saleOrderShip = null;
        if (!saleOrder.getOrderCategory().equals("虚拟商品订单")) {
            CustomerAddressInfo customerAddress = customerAddressInfos.get(0);
            saleOrderShip = new SaleOrderShip();
            saleOrderShip.setSoNo(saleOrder.getSaleNo());
            saleOrderShip.setCity(customerAddress.getCity());
            saleOrderShip.setCityZone(customerAddress.getCityZone());
            saleOrderShip.setConsignee(customerAddress.getConsignee());
            saleOrderShip.setDetail(customerAddress.getAddressDetail());
            saleOrderShip.setMobile(customerAddress.getMobileNo());
            saleOrderShip.setPrivince(customerAddress.getProvince());
            saleOrderShip.setCreatedBy("system");
            saleOrderShip.setCreatedTime(now);
            saleOrderShip.setModifiedBy("system");
            saleOrderShip.setModifiedTime(now);
        }

        //region 检查库存
        boolean isFullStock = this.checkStock(saleOrderItemList,orderInfo);
        if (!isFullStock){
            StringBuffer temp = new StringBuffer();
            if(null != orderInfo.getOutStockItemList()) {
                for (OrderStatusInfo.OutStockItemInfo itemInfo : orderInfo.outStockItemList) {
                    temp.append("," + itemInfo.getItemId());
                }
            }
            throw new ServiceException(OrderErrorCodes.errorCodes_OUT_OF_STOCK_ERROR,temp.toString());
        }
        //endregion

        //占用库存
        HashMap<String, String> deductStockMap = deductStock(saleOrderItemList);
        if (deductStockMap == null || deductStockMap.get("status").equals("false")) {
            logger.error("[创建订单|占用库存 in 创建订单方法] 报错");
            logger.error("[报错信息] code=" + deductStockMap.get("code"));
            throw new ServiceException(OrderErrorCodes.errorCodes_GENERATER_ORDER_STOCK_ERROR, deductStockMap.get("msg"));
        }

        //使用优惠券
        HashMap<String, String> promotionLogoffMap = promotionLogoff(calculationDTO, saleOrder.getSaleNo());
        if (promotionLogoffMap == null || promotionLogoffMap.get("status").equals("false")) {
            logger.error("[创建订单|使用优惠券 in 创建订单方法] 报错");
            logger.error("[报错信息] couponid=" + Json.toJson(calculationDTO.getPromoDiscountList()));

            //退回库存
            rollbackStock(saleOrderItemList);
            //退回成功的优惠券
            if (promotionLogoffMap.containsKey("sucessCode")) {
                long couponId = Long.parseLong(promotionLogoffMap.get("sucessCode"));
                promotionRecovery(couponId);
            }
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_PROMOTION_USE_ERROR, promotionLogoffMap.get("msg"));
        }

        try {
            createOrder(saleOrder, saleOrderItemList, saleOrderShip);
            orderInfo.setSaleNo(saleOrder.getSaleNo());
            orderInfo.setStatus(saleOrder.getStatus());
            orderInfo.setStatusValue(OrderStatusMapping(saleOrder.getStatus(), saleOrder.getPayType(), saleOrder.getOrderCategory(), saleOrder.getPayStatus()));
            orderInfo.setPayType(saleOrder.getPayType());
        } catch (Exception ex) {
            //订单创建失败时 退回库存
            rollbackStock(saleOrderItemList);
            //订单创建失败时 退回优惠券
            if (calculationDTO != null && calculationDTO.getPromoDiscountList() != null && calculationDTO.getPromoDiscountList().size() > 0) {
                List<PromoDiscountInfo> promoDiscountInfos = calculationDTO.getPromoDiscountList();
                for (PromoDiscountInfo promoDiscountInfo : promoDiscountInfos) {
                    promotionRecovery(promoDiscountInfo.getPromoId());
                }
            }

            logger.error("[创建订单|保存订单 in 创建订单方法] 报错");
            logger.error("[报错信息] 保存数据库失败");
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_GENERATER_ORDER_ERROR, "[创建订单|保存订单 in 创建订单方法] 报错 保存数据库失败");
        }
        //拆分优惠
        splitOrderPromotion(calculationDTO, cartGetInfo, saleOrderItemList, saleOrder);
        //清除购物车
        cartClean(saleOrderItemList, customer_id, deviceId);
        //占用下单量
        delDaliyLimitCache(saleOrder.getShipDate());
        //保存首单
        saveFristOrder(saleOrder.getSaleNo(), saleOrder.getCustomerId());
        //跟踪亿起发cps信息
        cps(emar_source, emar_channel, emar_cid, emar_wi, saleOrder.getSaleNo());

        //region  预警邮件

        //订单帐不平预警（订单的最总金额和优惠金额不相等）
        if(saleOrder.getTotalAmount().equals(
                saleOrder.getSubAmount().subtract(saleOrder.getPromotionDiscount()).subtract(saleOrder.getProductCouponDiscount())
                        .add(saleOrder.getShipFee()).subtract(saleOrder.getShipFeeDiscount()).subtract(saleOrder.getShipFeeCouponDiscount())
            )
        )
        {
            String content = " saleOrder:\r\n"
                    + Json.toJson(saleOrder)+"\r\n"
                    + "cartGetInfo:\r\n"
                    + Json.toJson(cartGetInfo);
            sendYJEmail("(订单帐不平)",content);
        }

        //endregion 预警邮件

        return orderInfo;
    }

    //region--------------begin 保存创建订单信息（事务）

    /**
     * 创建订单事务
     */
    @Transactional
    public void createOrder(SaleOrder saleOrder, List<SaleOrderItem> saleOrderItemList, SaleOrderShip saleOrderShip) throws Exception {
        if (saleOrderShip != null) {
            int OrderShip_int = saleOrderShipLogic.insert(saleOrderShip);
        }
        for (SaleOrderItem saleOrderItem : saleOrderItemList) {
            int orderItem_int = saleOrderItemLogic.insertSelective(saleOrderItem);
        }
        int order_int = saleOrderLogic.insert(saleOrder);
    }

    //endregion--------------end 保存创建订单信息（事务）

    //region  优惠券管理
    private HashMap promotionLogoff(CalculationDTO calculationDTO, String sale_no) {
        HashMap<String, String> rsMap = new HashMap<String, String>();

        if (calculationDTO == null) {
            rsMap.put("status", "true");
            return rsMap;
        }

        List<PromoDiscountInfo> promoDiscountInfos = calculationDTO.getPromoDiscountList();
        if (promoDiscountInfos == null || promoDiscountInfos.size() == 0) {
            rsMap.put("status", "true");
            return rsMap;
        }
        for (PromoDiscountInfo promoDiscountInfo : promoDiscountInfos) {
            long promotionId = promoDiscountInfo.getPromoId();
            String ruslt = "";
            try {
                ruslt = promoService.logoffCode(promotionId, sale_no);
            } catch (Exception ex) {
                logger.error("【优惠券服务|使用优惠券 in 使用优惠券方法】 报错 exmsg=" + ex.getMessage());
                logger.error("【报错信息】 id=" + promotionId + "  sale_no=" + sale_no);
                logger.error(ex);

                rsMap.put("status", "false");
                rsMap.put("code", "SerivceError");
                rsMap.put("msg", "【优惠券服务|使用优惠券 in 使用优惠券方法】 exMsg=" + ex.getMessage());
                return rsMap;
            }

            if (!ruslt.equals("T")) {
                logger.error("【优惠券服务|使用优惠券 in 使用优惠券方法】 异常 ruslt=" + ruslt);
                logger.error("【报错信息】 id=" + promotionId + "  sale_no=" + sale_no);

                rsMap.put("status", "false");
                rsMap.put("code", "SerivceError");
                rsMap.put("msg", "【优惠券服务|使用优惠券 in 使用优惠券方法】 异常 ruslt" + ruslt);
                return rsMap;
            }
            rsMap.put("sucessCode", Long.toString(promotionId));
        }

        rsMap.put("status", "true");
        return rsMap;
    }

    /**
     * 退还优惠券
     *
     * @param saleOrder
     * @return
     */
    private HashMap promotionRecoveryBySaleOrder(SaleOrder saleOrder) {
        HashMap<String, String> rsMap = new HashMap<String, String>();
        rsMap.put("status", "true");

        if (saleOrder == null) {
            return rsMap;
        }
        //查询使用的优惠券
        SaleOrderItemPromotionCriteria saleOrderItemPromotionCriteria = new SaleOrderItemPromotionCriteria();
        saleOrderItemPromotionCriteria.createCriteria().andSoNoEqualTo(saleOrder.getSaleNo()).andCouponCodeNotEqualTo("0");

        List<SaleOrderItemPromotion> saleOrderItemPromotions = null;

        try {
            saleOrderItemPromotions = saleOrderItemPromotionLogic.list(saleOrderItemPromotionCriteria);
        } catch (Exception ex) {
            logger.error("[优惠券服务|退还优惠券 in 退还优惠券方法] 报错");
            logger.error(ex);

            rsMap.put("status", "false");
            rsMap.put("code", "SerivceError");
            rsMap.put("msg", "[优惠券服务|退还优惠券 in 退还优惠券方法] exMsg=" + ex.getMessage());
            return rsMap;
        }

        try {
            if (saleOrderItemPromotions != null && saleOrderItemPromotions.size() > 0) {
                //退过券的集合
                HashMap<String, String> promotins = new HashMap<String, String>();

                for (SaleOrderItemPromotion saleOrderItemPromotion : saleOrderItemPromotions) {
                    if (!promotins.containsKey(saleOrderItemPromotion.getCouponCode())) {
                        promotionRecovery(Long.parseLong(saleOrderItemPromotion.getCouponCode()));
                        promotins.put(saleOrderItemPromotion.getCouponCode(), saleOrderItemPromotion.getCouponCode());
                    }

                    //修改优惠券记录状态
                    saleOrderItemPromotion.setIsValid(0);
                    try {
                        saleOrderItemPromotionLogic.update(saleOrderItemPromotion);
                    } catch (Exception e) {
                        logger.error("[优惠券服务|更新优惠券记录 in 退还优惠券方法] 报错");
                        logger.error("[错误信息] saleOrderItemPromotion=" + Json.toJson(saleOrderItemPromotion));
                        logger.error(e);
                    }

                }
            }
        } catch (Exception ex) {
            logger.error("[优惠券服务|退还优惠券逻辑 in 退还优惠券方法] 报错");
            logger.error(ex);

            rsMap.put("status", "false");
            rsMap.put("code", "SerivceError");
            rsMap.put("msg", "[优惠券服务|退还优惠券逻辑 in 退还优惠券方法] exMsg=" + ex.getMessage());
            return rsMap;
        }
        return rsMap;
    }


    /**
     * 退还优惠券
     *
     * @param couponId
     * @return
     */
    private HashMap promotionRecovery(long couponId) {
        HashMap<String, String> rsMap = new HashMap<String, String>();
        if (couponId == 0) {
            rsMap.put("status", "true");
            return rsMap;
        }

        String resutl = "";

        try {
            logger.debug("debug[优惠券服务|退还优惠券 in 退还优惠券方法] couponId=" + couponId);
            resutl = promoService.recoveryCode(couponId);
        } catch (Exception ex) {
            logger.error("【优惠券服务|退还优惠券 in 退还优惠券方法】 报错");
            logger.error("【报错信息】 couponId=" + couponId);
            logger.error(ex);

            rsMap.put("status", "false");
            rsMap.put("code", "SerivceError");
            rsMap.put("msg", "【优惠券服务|退还优惠券 in 退还优惠券方法】 报错 exMsg=" + ex.getMessage());
            return rsMap;
        }

        if (!resutl.equals("T")) {
            logger.error("【优惠券服务|退还优惠券 in 退还优惠券方法】 异常");
            logger.error("【报错信息】 couponId=" + couponId);

            rsMap.put("status", "false");
            rsMap.put("code", "SerivceError");
            rsMap.put("msg", "【优惠券服务|退还优惠券 in 退还优惠券方法】 报错 resutl=" + resutl);
            return rsMap;
        }
        rsMap.put("status", "true");
        return rsMap;
    }

    //#endregion 优惠券管理

    //region--------------begin 库存管理

    /**
     * 修改库存字符串
     *
     * @param saleOrderItemList
     * @return
     */
    private String getStockStr(List<SaleOrderItem> saleOrderItemList) {
        List<ItemStockDTO> itemStockDTOs = new ArrayList<ItemStockDTO>();
        if (saleOrderItemList != null && saleOrderItemList.size() > 0) {
            for (SaleOrderItem saleOrderItem : saleOrderItemList) {
                ItemStockDTO itemStockDTO = new ItemStockDTO();
                itemStockDTO.setId(saleOrderItem.getItemId());
                itemStockDTO.setNum(saleOrderItem.getQuantity());
                itemStockDTOs.add(itemStockDTO);
            }
        }
        return Json.toJson(itemStockDTOs);
    }

    /**
     * 占用库存
     *
     * @param saleOrderItemList
     */
    private HashMap deductStock(List<SaleOrderItem> saleOrderItemList) {
        HashMap<String, String> rsMap = new HashMap<String, String>();

        String StockStr = getStockStr(saleOrderItemList);
        if (StockStr == null || StockStr.isEmpty()) {
            logger.error("[占用库存|组装库存数据 in 占用库存方法] 报错");

            rsMap.put("status", "false");
            rsMap.put("code", "ExecFailure");
            rsMap.put("msg", "[占用库存|组装库存数据 in 占用库存方法] 报错 请求参数参数");
            return rsMap;
        }

        ProductsStockResponse productsStockResponse;
        try {
            productsStockResponse = stockService.deductProductStock(StockStr);
        } catch (Exception ex) {
            logger.error("【库存服务|占用库存 in 占用库存方法】 报错");
            logger.error("【报错信息】StockStr =" + StockStr);
            logger.error(ex);
            rsMap.put("status", "false");
            rsMap.put("code", "ServiceFailure");
            rsMap.put("msg", "【库存服务|占用库存 in 占用库存方法】 报错 服务报错");
            return rsMap;
        }

        boolean stockStatus = true;
        long itemid = 0;
        if (productsStockResponse != null && productsStockResponse.getProductsStock() != null && productsStockResponse.getProductsStock().size() > 0) {

            for (ProductStockResponse productStockResponse : productsStockResponse.getProductsStock()) {
                if (productStockResponse.getStock() < 0) {
                    stockStatus = false;
                    itemid = productStockResponse.getId();
                    break;
                }
            }
        }

        if (!stockStatus) {
            logger.error("【库存服务|占用库存 in 占用库存方法】 库存不足 StockStr=" + StockStr);
            rsMap.put("status", "false");
            rsMap.put("code", "ServiceFailure");

            String itemname = "";
            //如果库存不足，就返回具体消息
            for (SaleOrderItem saleOrderItem : saleOrderItemList) {
                if (saleOrderItem.getItemId() == itemid) {
                    itemname = saleOrderItem.getItemTitle();
                }
            }

            rsMap.put("msg", "商品 【" + itemname + "】 库存不足");
            return rsMap;
        }
        rsMap.put("status", "true");
        return rsMap;
    }

    /**
     * 取消库存
     */
    private void rollbackStock(String sale_no) throws ServiceException {
        List<SaleOrderItem> list = getOrderItemList(sale_no);
        if (list != null) {
            rollbackStock(list);
        }
    }

    /**
     * 释放库存
     *
     * @param saleOrderItemList
     */
    private HashMap<String, String> rollbackStock(List<SaleOrderItem> saleOrderItemList) {
        HashMap<String, String> rsMap = new HashMap<String, String>();

        String StockStr = getStockStr(saleOrderItemList);
        if (StockStr == null || StockStr.isEmpty()) {
            rsMap.put("status", "false");
            rsMap.put("code", "NoStockStr");
            rsMap.put("msg", "[退回库存|退回库存 in 退回库存方法] 报错 code= NoStockStr");
            logger.error("[退回库存|退回库存 in 退回库存方法] 报错 code= NoStockStr");
            return rsMap;
        }

        ProductsStockResponse productsStockResponse;
        try {
            productsStockResponse = stockService.rollbackStock(StockStr);
        } catch (Exception ex) {
            rsMap.put("status", "false");
            rsMap.put("code", "NoStockStr");
            rsMap.put("msg", "【库存服务|还原库存 in 还原库存方法】 报错 msg=" + ex.getMessage());
            logger.error("【库存服务|还原库存 in 还原库存方法】 报错 msg=" + ex.getMessage());
            logger.error("【报错信息】 StockStr=" + StockStr);
            logger.error(ex);
            return rsMap;
        }

        boolean stockStatus = true;
        long productid = 0;

        if (productsStockResponse != null && productsStockResponse.getProductsStock() != null && productsStockResponse.getProductsStock().size() > 0) {

            for (ProductStockResponse productStockResponse : productsStockResponse.getProductsStock()) {
                if (productStockResponse.getStock() < 0) {
                    stockStatus = false;
                    productStockResponse.getId();
                    break;
                }
            }
        }

        if (!stockStatus) {
            rsMap.put("status", "false");
            rsMap.put("code", "ServiceError");
            rsMap.put("msg", "【库存服务|还原库存 in 还原库存方法】 报错 code=ServiceError");
            logger.error("【库存服务|还原库存 in 还原库存方法】 报错 code=ServiceError");
            logger.error("【报错信息】 StockStr=" + StockStr);
            return rsMap;
        }
        rsMap.put("status", "true");
        return rsMap;
    }

    //endregion--------------end 库存管理

    //region--------------begin 清除购物车

    /**
     * 清楚购物车
     */
    private void cartClean(List<SaleOrderItem> saleOrderItemList, String customer_id, String deviceId) {
        //清除购物车
        try {
            if (saleOrderItemList != null && saleOrderItemList.size() > 0) {
                List<ItemIdNumDTO> itemIdNumDTOs = new ArrayList<ItemIdNumDTO>();
                for (SaleOrderItem saleOrderItem : saleOrderItemList) {
                    ItemIdNumDTO itemIdNumDTO = new ItemIdNumDTO();
                    itemIdNumDTO.setItemId(saleOrderItem.getItemId());
                    itemIdNumDTO.setNum(saleOrderItem.getQuantity());
                    itemIdNumDTOs.add(itemIdNumDTO);
                }
                RpcContext.getContext().setAttachment(CommonParameter.userId, customer_id);
                RpcContext.getContext().setAttachment(CommonParameter.deviceId, deviceId);
                CartSimpleResponse cartSimpleResponse = cartService.cartClean(Json.toJson(itemIdNumDTOs));
            }

        } catch (Exception ex) {
            logger.error("清除购物车失败");
            logger.error(ex);
        }
    }

    //endregion------------end 清除购物车

    // region--------------begin 提交订单时优惠拆分

    //拆分订单优惠
    private void splitOrderPromotion(CalculationDTO calculationDTO, CartGetInfo cartGetInfo, List<SaleOrderItem> saleOrderItems, SaleOrder saleOrder) {
        //目前只有普通订单才拆分优惠
        if (!saleOrder.getOrderCategory().equals("普通订单")) {
            return;
        }

        //所有商品map  用途1：优惠根据id找商品   用途2：保存记录前根据itemid找saleorderitem id
        Map<Long, SaleOrderItem> mapOrderItem = new HashMap<Long, SaleOrderItem>();
        if (saleOrderItems != null && saleOrderItems.size() > 0) {
            for (SaleOrderItem saleOrderItem : saleOrderItems) {
                if (!mapOrderItem.containsKey(saleOrderItem.getItemId().toString())) {
                    mapOrderItem.put(saleOrderItem.getItemId(), saleOrderItem);
                }
            }
        }

        //拆出来优惠&优惠券
        List<SaleOrderItemPromotion> saleOrderItemPromotions = new ArrayList<SaleOrderItemPromotion>();

        //优惠券拆分
        if (calculationDTO != null && calculationDTO.getPromoDiscountList() != null && calculationDTO.getPromoDiscountList().size() > 0) {
            List<PromoDiscountInfo> promoDiscountInfos = calculationDTO.getPromoDiscountList();
            for (PromoDiscountInfo promoDiscountInfo : promoDiscountInfos) {
                //得到优惠与对应商品
                List<PromotionSplitDTO> promotionSplitDTOs = new ArrayList<PromotionSplitDTO>();
                PromotionSplitDTO promotionSplitDTO = new PromotionSplitDTO();
                promotionSplitDTO.setAmount(promoDiscountInfo.getDiscount());
                promotionSplitDTO.setPromotionId(0);
                promotionSplitDTO.setType("REDUCE");
                promotionSplitDTO.setCouponSelfId(promoDiscountInfo.getPromoId());
                promotionSplitDTO.setCouponProviderId(promoDiscountInfo.getPromoId());

                List<ItemsDTO> itemsDTOs = new ArrayList<ItemsDTO>();
                //根据id找item
                if (promoDiscountInfos != null && promoDiscountInfo.getItems() != null && promoDiscountInfo.getItems().length > 0) {
                    long[] itemId = promoDiscountInfo.getItems();
                    for (long id : itemId) {
                        //找商品
                        if (mapOrderItem.containsKey(id)) {
                            SaleOrderItem saleOrderItem = mapOrderItem.get(id);
                            ItemsDTO itemsDTO = new ItemsDTO();
                            itemsDTO.setId(id);
                            itemsDTO.setNum(saleOrderItem.getQuantity());
                            itemsDTO.setRetailPrice(saleOrderItem.getUnitPrice().doubleValue());
                            itemsDTOs.add(itemsDTO);
                        }
                    }
                }
                promotionSplitDTO.setItemsDTOs(itemsDTOs);

                promotionSplitDTOs.add(promotionSplitDTO);

                //根据优惠与对应商品分摊价钱
                if (promotionSplitDTOs != null && promotionSplitDTOs.size() > 0) {
                    //拆分金额到具体商品上
                    List<SaleOrderItemPromotion> saleOrderItemPromotionList = splitPromotionAmountToItem(promotionSplitDTOs, saleOrder.getSaleNo());
                    if (saleOrderItemPromotionList != null && saleOrderItemPromotionList.size() > 0) {
                        saleOrderItemPromotions.addAll(saleOrderItemPromotionList);
                    }
                }
            }
        }

        //2 优惠拆分
        if (cartGetInfo != null) {
            try {
                //分组信息
                List<GroupsDTO> groupsDTOList = cartGetInfo.getGroups();
                if (groupsDTOList != null && groupsDTOList.size() > 0) {
                    for (GroupsDTO groupsDTO : groupsDTOList) {
                        //具体的分组
                        if (groupsDTO != null) {
                            //得到优惠与对应商品
                            List<PromotionSplitDTO> promotionSplitDTOs = getPromotionSplitDto(groupsDTO);
                            //根据优惠与对应商品分摊价钱
                            if (promotionSplitDTOs != null && promotionSplitDTOs.size() > 0) {
                                //拆分金额到具体商品上
                                List<SaleOrderItemPromotion> saleOrderItemPromotionList = splitPromotionAmountToItem(promotionSplitDTOs, saleOrder.getSaleNo());
                                if (saleOrderItemPromotionList != null && saleOrderItemPromotionList.size() > 0) {
                                    saleOrderItemPromotions.addAll(saleOrderItemPromotionList);
                                }
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                logger.error("[拆分优惠|拆分优惠到子项 in 拆分优惠] 报错");
                logger.error(ex);
            }
        }

        //保存拆分结果
        //优惠总金额
        BigDecimal alldiscount = new BigDecimal(0);
        try {
            if (saleOrderItemPromotions != null && saleOrderItemPromotions.size() > 0) {
                for (SaleOrderItemPromotion saleOrderItemPromotion : saleOrderItemPromotions) {
                    if (mapOrderItem.containsKey(saleOrderItemPromotion.getSoItemId())) {
                        alldiscount.add(saleOrderItemPromotion.getDiscount());//优惠总金额
                        saleOrderItemPromotion.setSoItemId(mapOrderItem.get(saleOrderItemPromotion.getSoItemId()).getId());
                        saleOrderItemPromotionLogic.insertSelective(saleOrderItemPromotion);
                    } else {
                        logger.error("[拆分优惠|匹配itemId in 拆分优惠] 报错");
                        logger.error("[[报错信息] map=" + Json.toJson(mapOrderItem));
                    }
                }
            }
        } catch (Exception ex) {
            logger.error("[拆分优惠|保存结果到数据库 in 拆分优惠] 报错");
        }

        //优惠拆分预警
        if(saleOrder.getPromotionDiscount().add(saleOrder.getProductCouponDiscount()).equals(alldiscount))
        {
            String content = " saleOrder:\r\n"
                    + Json.toJson(saleOrder)+"\r\n"
                    + "cartGetInfo:\r\n"
                    + Json.toJson(cartGetInfo);
            sendYJEmail("(订单优惠拆分不平)",content);
        }
    }

    /**
     * 解析 优惠对应的商品，及优惠结果
     *
     * @param groupsDTO
     * @return
     */
    private List<PromotionSplitDTO> getPromotionSplitDto(GroupsDTO groupsDTO) {
        List<PromotionSplitDTO> promotionSplitDTOs = new ArrayList<>();

        //具体的分组
        if (groupsDTO != null) {
            //单品
            List<ItemsDTO> itemsDTOList = groupsDTO.getSingle();
            if (itemsDTOList != null && itemsDTOList.size() > 0) {
                for (ItemsDTO itemsDTO : itemsDTOList) {
                    //单品的优惠
                    List<PromotionsDTO> promotionsDTOs = itemsDTO.getPromotions();
                    List<ItemsDTO> splitItems = new ArrayList<ItemsDTO>();
                    splitItems.add(itemsDTO);

                    promotionSplitDTOs.addAll(promotionSplitDTOs(promotionsDTOs, splitItems));
                }
            }

            //专区
            List<CombineDTO> combineDTOs = groupsDTO.getCombine();
            if (combineDTOs != null && combineDTOs.size() > 0) {
                for (CombineDTO combineDTO : combineDTOs) {
                    if (combineDTO != null) {
                        List<ItemsDTO> itemsDTOs_combine = combineDTO.getItems();
                        for (ItemsDTO itemsDTO : itemsDTOs_combine) {
                            //单品的优惠
                            List<PromotionsDTO> promotionsDTOs = itemsDTO.getPromotions();
                            List<ItemsDTO> splitItems = new ArrayList<ItemsDTO>();
                            splitItems.add(itemsDTO);

                            promotionSplitDTOs.addAll(promotionSplitDTOs(promotionsDTOs, splitItems));
                        }

                        //专区的优惠
                        List<PromotionsDTO> promotionsDTOs = combineDTO.getPromotions();
                        //专区的商品
                        promotionSplitDTOs.addAll(promotionSplitDTOs(promotionsDTOs, itemsDTOs_combine));

                    }
                }
            }
        }
        return promotionSplitDTOs;
    }

    /**
     * 各种优惠的解析
     *
     * @param promotionsDTOs
     * @param itemsDTOs
     * @return
     */
    private List<PromotionSplitDTO> promotionSplitDTOs(List<PromotionsDTO> promotionsDTOs, List<ItemsDTO> itemsDTOs) {
        List<PromotionSplitDTO> promotionSplitDTOs = new ArrayList<PromotionSplitDTO>();

       /* 1	REDUCE	满额减，满199减50，满299减70等
        2	GIVE	满额送，满199送澳洲大青龙，满299送西班牙美女等
        3	PIECEREDUCE	满件减，购买澳洲牛骨2份减80元
        4	PIECEGIVE	满件送，购买西冷牛排3份送苏泊尔牛排锅
        5	OPTIONALLY	N元M件，99元专区任选3件，199元专区任选4件等
        6	SPECIAL	限时特价
        7	FIRSTREDUCE	首单满额减，用户首次下单，订单金额满99减30元
        8	FIRSTGIVE	首单满额送，用户首次下单，订单金额满99送赣南橙一箱*/

        if (promotionsDTOs != null && promotionsDTOs.size() > 0) {
            for (PromotionsDTO promotionsDTO : promotionsDTOs) {
                //优惠的类型，不同的优惠，不同处理方式
                String type = promotionsDTO.getType();

                if (type.equals("REDUCE")//满额减，满199减50，满299减70等
                        || type.equals("PIECEREDUCE"))//满件减，购买澳洲牛骨2份减80元
                {
                    double allAmount = 0;
                    List<UseRuleDTO> useRuleDTOs = promotionsDTO.getRule();
                    if (useRuleDTOs != null && useRuleDTOs.size() > 0) {
                        for (UseRuleDTO useRuleDTO : useRuleDTOs) {
                            allAmount += useRuleDTO.getPreferential();
                        }

                        PromotionSplitDTO promotionSplitDTO = new PromotionSplitDTO();
                        promotionSplitDTO.setAmount(allAmount);
                        promotionSplitDTO.setType("REDUCE");
                        promotionSplitDTO.setPromotionType(type);
                        promotionSplitDTO.setItemsDTOs(itemsDTOs);
                        promotionSplitDTO.setPromotionId(promotionsDTO.getId());
                        promotionSplitDTOs.add(promotionSplitDTO);
                    }
                } else if (type.equals("SPECIAL"))//限时特价
                {
                    //计算商品总金额
                    double allItemAmount = 0;
                    for (ItemsDTO itemsDTO : itemsDTOs) {
                        allItemAmount += itemsDTO.getRetailPrice() * itemsDTO.getNum();
                    }

                    double allAmount = 0;
                    List<UseRuleDTO> useRuleDTOs = promotionsDTO.getRule();
                    if (useRuleDTOs != null && useRuleDTOs.size() > 0) {
                        for (UseRuleDTO useRuleDTO : useRuleDTOs) {
                            allAmount += useRuleDTO.getPreferential();
                        }
                        allAmount = allItemAmount - allAmount;


                        PromotionSplitDTO promotionSplitDTO = new PromotionSplitDTO();
                        promotionSplitDTO.setAmount(allAmount);
                        promotionSplitDTO.setType("REDUCE");
                        promotionSplitDTO.setPromotionType(type);
                        promotionSplitDTO.setItemsDTOs(itemsDTOs);
                        promotionSplitDTO.setPromotionId(promotionsDTO.getId());
                        promotionSplitDTOs.add(promotionSplitDTO);
                    }
                } else if (type.equals("GIVE") || type.equals("PIECEGIVE")) //满额送，满199送澳洲大青龙，满299送西班牙美女等
                {
                    //赠品不拆分优惠,只做记录

                    if (promotionsDTO.getGiftItem() != null && promotionsDTO.getGiftItem().size() > 0) {
                        PromotionSplitDTO promotionSplitDTO = new PromotionSplitDTO();
                        promotionSplitDTO.setAmount(0);
                        promotionSplitDTO.setType("GIVE");
                        promotionSplitDTO.setPromotionType(type);
                        promotionSplitDTO.setItemsDTOs(promotionsDTO.getGiftItem());
                        promotionSplitDTO.setPromotionId(promotionsDTO.getId());
                        promotionSplitDTOs.add(promotionSplitDTO);
                    }
                } else if (type.equals("OPTIONALLY")) //N元M件，99元专区任选3件，199元专区任选4件等
                {
                    //计算优惠了多少钱

                    //优惠规则
                    UseRuleDTO useRuleDTOs = promotionsDTO.getRule().get(0);
                    //多钱
                    Double Preferential = useRuleDTOs.getPreferential();
                    //n件
                    int count = (int) useRuleDTOs.getLimit();

                    //倒序排列下商品
                    Collections.sort(itemsDTOs, new Comparator<ItemsDTO>() {
                        public int compare(ItemsDTO arg0, ItemsDTO arg1) {
                            return arg0.getRetailPrice() - arg1.getRetailPrice() > 0.00001 ? -1 : 1;
                        }
                    });


                    double allAmount = 0;    //总金额
                    int allcount = 0;  //个数
                    for (int i = 0; i < itemsDTOs.size(); i++) {
                        ItemsDTO itemsDTO = itemsDTOs.get(i);

                        allcount += itemsDTO.getNum();
                        if (allcount <= count) {
                            allAmount += itemsDTO.getRetailPrice() * itemsDTO.getNum();
                            if (allcount == count) {
                                break;
                            }
                        } else {
                            allAmount += itemsDTO.getRetailPrice() * (count - allcount);
                            break;
                        }
                    }

                    double amount = allAmount - Preferential;
                    PromotionSplitDTO promotionSplitDTO = new PromotionSplitDTO();
                    promotionSplitDTO.setAmount(amount);
                    promotionSplitDTO.setType("REDUCE");
                    promotionSplitDTO.setPromotionType(type);
                    promotionSplitDTO.setItemsDTOs(itemsDTOs);
                    promotionSplitDTO.setPromotionId(promotionsDTO.getId());
                    promotionSplitDTOs.add(promotionSplitDTO);
                } else if (type.equals("FIRSTREDUCE")) //首单满额减，用户首次下单，订单金额满99减30元
                {
                    //现在还没有
                } else if (type.equals("FIRSTGIVE")) //首单满额送，用户首次下单，订单金额满99送赣南橙一箱
                {
                    //现在还没有
                }
            }
        }
        return promotionSplitDTOs;
    }

    /**
     * 拆分金额到具体的商品上
     *
     * @param promotionSplitDTOs
     * @param sono
     * @return
     */
    private List<SaleOrderItemPromotion> splitPromotionAmountToItem(List<PromotionSplitDTO> promotionSplitDTOs, String sono) {
        List<SaleOrderItemPromotion> saleOrderItemPromotions = new ArrayList<SaleOrderItemPromotion>();

        DecimalFormat df = new DecimalFormat("####0.00");

        //循环去拆分每个优惠
        if (promotionSplitDTOs != null && promotionSplitDTOs.size() > 0) {


            for (PromotionSplitDTO promotionSplitDTO : promotionSplitDTOs) {
                //商品
                List<ItemsDTO> itemsDTOs = promotionSplitDTO.getItemsDTOs();
                //已减金额
                double amount = promotionSplitDTO.getAmount();
                //coupon_self_id
                long coupon_self_id = promotionSplitDTO.getCouponSelfId();
                //coupon_provider_id
                long coupon_provider_id = promotionSplitDTO.getCouponProviderId();
                //promotionid
                long promotionid = promotionSplitDTO.getPromotionId();
                String type = promotionSplitDTO.getType();
                if (itemsDTOs != null && itemsDTOs.size() > 0) {
                    if (type.equals("GIVE")) {
                        //** 赠品的先不处理
                    } else if (type.equals("REDUCE")) {
                        //计算商品总金额
                        double allAmount = 0;
                        for (ItemsDTO itemsDTO : itemsDTOs) {
                            allAmount += itemsDTO.getRetailPrice() * itemsDTO.getNum();
                        }

                        //已经分摊的金额
                        double allSplitAmount = 0;

                        for (int i = 0; i < itemsDTOs.size(); i++) {
                            ItemsDTO itemsDTO = itemsDTOs.get(i);

                            SaleOrderItemPromotion saleOrderItemPromotion = new SaleOrderItemPromotion();
                            saleOrderItemPromotion.setSoNo(sono);
                            saleOrderItemPromotion.setSoItemId(itemsDTO.getId());
                            saleOrderItemPromotion.setPromotionId(promotionid);
                            if (coupon_self_id != 0) {
                                saleOrderItemPromotion.setCouponCode(Long.toString(coupon_self_id));
                            } else if (coupon_provider_id != 0) {
                                saleOrderItemPromotion.setCouponCode(Long.toString(coupon_provider_id));
                            } else {
                                saleOrderItemPromotion.setCouponCode(Long.toString(0));
                            }
                            saleOrderItemPromotion.setIsValid(1);
                            saleOrderItemPromotion.setModifiedBy("system");
                            saleOrderItemPromotion.setModifiedTime(new Date());
                            saleOrderItemPromotion.setCreatedBy("system");
                            saleOrderItemPromotion.setCreatedTime(new Date());

                            if (i < (itemsDTOs.size() - 1)) {
                                //按比例分摊金额
                                double itemAmount = itemsDTO.getRetailPrice() * itemsDTO.getNum();
                                double splitAmount = Double.valueOf(df.format((itemAmount / allAmount) * amount));
                                saleOrderItemPromotion.setDiscount(new BigDecimal(splitAmount));
                                allSplitAmount += splitAmount;
                            } else {
                                //如果是最后一个商品，优惠金额减去已分摊金额
                                saleOrderItemPromotion.setDiscount(new BigDecimal(amount - allSplitAmount));
                            }
                            //加入分摊好的组中
                            saleOrderItemPromotions.add(saleOrderItemPromotion);
                        }
                    }
                }
            }
        }
        return saleOrderItemPromotions;
    }

    //endregion--------------end 提交订单时优惠拆分

    /**
     * 支付页面信息
     *
     * @param sale_no
     * @return
     * @throws ServiceException
     */
    @Override
    public PagePayInfo pagePay(@ApiParameter(required = true, name = "sale_no", desc = "订单号") String sale_no) throws ServiceException {

        PagePayInfo pagePayInfo = new PagePayInfo();

        //公共参数
        //appid
        String appID = RpcContext.getContext().getAttachment(CommonParameter.applicationId);
        String userId = RpcContext.getContext().getAttachment(CommonParameter.userId);
        String terminal = RpcContext.getContext().getAttachment(ExtendParameter.terminal);

        AccountBalance accountBalance = null;
        try{
            accountBalance = memberService.getBalance();
            if (accountBalance == null) {
                logger.warn("【会员服务|获取余额】 accountBalance == null");
                throw new ServiceException(OrderErrorCodes.errorCodes_USERBALANCE_NOT_FOUND);
            }
        }catch (Exception ex)
        {
            logger.warn("【会员服务|获取余额】 报错 info="
                    + userId
                    + "  msg=" + ex.getMessage());
            throw new ServiceException(OrderErrorCodes.errorCodes_USERBALANCE_NOT_FOUND,"【【会员服务|获取余额】 报错 信息："+ex.getMessage());
        }

        pagePayInfo.setBalance(accountBalance.getBalance());

        //待付金额
        SaleOrder order = getOrderBySo(sale_no);
        if (order == null) {
            logger.warn("not found order in pagpay: saleno:" + sale_no);
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        } else if (order.getPayStatus() == com.ulife.order.service.enumeration.SaleOrderPayStatus.Paid.value()) {
            logger.warn("order cannot pay in pagpay: saleno:" + sale_no);
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_CANNOTPAY);
        }
        //默认
        pagePayInfo.setUseBalance(true);
        pagePayInfo.setWaitPaidAmount(order.getTotalAmount().subtract(order.getPaidAmount()).doubleValue());

        //检验
        if(order.getOrderCategory().equals("团购订单")||order.getOrderCategory().equals("市场部拉新订单")||order.getOrderCategory().equals("虚拟商品订单")){
            pagePayInfo.setUseBalance(false);
        }
        if (pagePayInfo.getWaitPaidAmount() <= 0) {
            logger.warn("order waitpaidamount error in pagepay: saleno:" + sale_no);
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_CANNOTPAY);
        }

        //【获取商品可用支付信息】
        List<SaleOrderItem> saleOrderItemList = getOrderItemList(sale_no);
        StringBuffer sbfItemIDs = new StringBuffer();
        for (SaleOrderItem saleOrderItem : saleOrderItemList) {
            if (sbfItemIDs.toString().length() != 0) {
                sbfItemIDs.append(",");
            }
            sbfItemIDs.append(saleOrderItem.getItemId());
        }
        List<PayTypeResponse> payTypeResponses = null;
        try {
            payTypeResponses = productService.getPayments(sbfItemIDs.toString());

            if (order.getOrderCategory().equals("团购订单")) {
                logger.info("[商品服务|获取商品支付列表] 请求信息=" + sbfItemIDs.toString() + "  返回信息=" + Json.toJson(payTypeResponses));
            }
        } catch (Exception ex) {
            logger.error("【商品服务|获取支付方式】 失败 请求信息："+sbfItemIDs.toString());
            logger.error(ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_PRODUCTPAYMENT_NOT_FOUND,"【商品服务|获取支付方式】 失败 请求信息："+sbfItemIDs.toString());
        }

         /*
                app   wap   web   ->  value
                0     0     0         0
                0     0     1         1
                0     1     0         2
                0     1     1         3
                1     0     0         4
                1     0     1         5
                1     1     0         6
                1     1     1         7
                */
        List<Integer> displayList = new ArrayList<>();

        boolean isWapOrApp = false;
        //根据appid取图片地址
        if (appID.equals("2001")) {
            //官网
            displayList = new ArrayList<>();
            displayList.add(1);
            displayList.add(3);
            displayList.add(5);
            displayList.add(7);
        } else if (appID.equals("1001") || appID.equals("1006")) {
            //wap
            isWapOrApp = true;
            displayList.add(2);
            displayList.add(3);
            displayList.add(6);
            displayList.add(7);
        } else if (appID.equals("1004") || appID.equals("1005")) {
            //app
            isWapOrApp = true;
            displayList.add(4);
            displayList.add(5);
            displayList.add(6);
            displayList.add(7);
        }
        //获取支付方式优惠
        List<PromoPayInfo> promoPayInfos = new ArrayList<>();
        try{
            RpcContext.getContext().setAttachment(CommonParameter.userId, userId);
            RpcContext.getContext().setAttachment(ExtendParameter.terminal,terminal);
            promoPayInfos = promoService.promoPayGetList(order.getSaleNo(), pagePayInfo.getWaitPaidAmount());
        }catch (Exception ex){
            logger.error("order.pagePay".concat(ex.getMessage()));
        }

        //组装页面可用的支付格式
        PayTypeInfo payTypeInfo_ONLINE = null; //线上支付
        //PayTypeInfo payTypeInfo_COD = null;  //其他支付
        for (PayTypeResponse payTypeResponse : payTypeResponses) {

            if (payTypeResponse.getCode().equals("ONLINE_PAY")) {
                payTypeInfo_ONLINE = new PayTypeInfo();
                dozerBeanMapper.map(payTypeResponse, payTypeInfo_ONLINE);
                payTypeInfo_ONLINE.setPayChannelList(null);
                for (PayChannelDTO payChannelDTO : payTypeResponse.getPayChannelList()) {
                    if (displayList.contains(payChannelDTO.getDisplay())) {
                        PayChannelInfo payChannelInfo_ONLINE = new PayChannelInfo();
                        dozerBeanMapper.map(payChannelDTO, payChannelInfo_ONLINE);
                        payChannelInfo_ONLINE.setIconUrl(payIcoUrl + payChannelInfo_ONLINE.getIconUrl());
                        //显示优惠
                        if (promoPayInfos != null && promoPayInfos.size() > 0) {
                            for (PromoPayInfo promoPayInfo : promoPayInfos) {
                                if (promoPayInfo.getChannelNo().equals(payChannelInfo_ONLINE.getChannelNo())) {
                                    if (!isWapOrApp) {
                                        payChannelInfo_ONLINE.setDescription(promoPayInfo.getPcTitle());
                                    } else {
                                        payChannelInfo_ONLINE.setDescription(promoPayInfo.getMobileTitle());
                                    }
                                }
                            }
                        }

                        if (payTypeInfo_ONLINE.getPayChannelList() == null) {
                            payTypeInfo_ONLINE.setPayChannelList(new ArrayList<PayChannelInfo>() {
                            });
                        }
                        payTypeInfo_ONLINE.getPayChannelList().add(payChannelInfo_ONLINE);
                    }
                }
            }
        }

        //设置默认在线支付方式， 默认支付宝，没有支付宝默认第一条
        if (payTypeInfo_ONLINE != null && payTypeInfo_ONLINE.getPayChannelList() != null && payTypeInfo_ONLINE.getPayChannelList().size() > 0) {
            boolean checkDefault = false;
            List<PayChannelInfo> payChannelInfoList = payTypeInfo_ONLINE.getPayChannelList();
            for (PayChannelInfo payChannelInfo : payChannelInfoList) {
                if (payChannelInfo.channelNo.equals("02") || payChannelInfo.channelNo.equals("06") || payChannelInfo.channelNo.equals("16")) {
                    payChannelInfo.setIsDefault(true);
                    checkDefault = true;
                    break;
                }
            }

            if (!checkDefault) {
                payChannelInfoList.get(0).setIsDefault(true);
            }
        }

        pagePayInfo.setPayTypeList(new ArrayList<PayTypeInfo>());
        pagePayInfo.getPayTypeList().add(payTypeInfo_ONLINE);
        return pagePayInfo;
    }

    /**
     * 去支付
     *
     * @param sale_no
     * @param channel_no
     * @param card_type
     * @param is_balance
     * @return
     * @throws ServiceException
     */
    @Override
    public PayResponse pay(@ApiParameter(required = true, name = "sale_no", desc = "订单号") String sale_no,
                           @ApiParameter(required = false, name = "channel_no", desc = "支付渠道") String channel_no,
                           @ApiParameter(required = false, name = "card_type", desc = "卡类型") String card_type,
                           @ApiParameter(required = false, name = "is_balance", desc = "是否余额支付") boolean is_balance,
                           @ApiParameter(required = false, name = "openid", desc = "微信openid") String openid,
                           @ApiParameter(required = false, name = "return_url", desc = "支付成功返回url") String return_url) throws ServiceException {

        // region 公共参数
        String customer_id = RpcContext.getContext().getAttachment(CommonParameter.userId);//Customer_id

        //app_id
        String app_id = RpcContext.getContext().getAttachment(CommonParameter.applicationId);
        //client_ip
        String client_ip = RpcContext.getContext().getAttachment(CommonParameter.clientIp);
        //platfrom
        String platform = (RpcContext.getContext().getAttachment(ExtendParameter.platform) == null) ?
                "" : (RpcContext.getContext().getAttachment(ExtendParameter.platform).toLowerCase());
        //当前时间
        Date now = new Date();
        //terminal
        String _terminal= RpcContext.getContext().getAttachment(ExtendParameter.terminal);
        //endregion

        if (client_ip != null && !client_ip.isEmpty()) {
            String[] client_ips = client_ip.split(",");
            client_ip = client_ips.length > 1 ? client_ips[0] : client_ip;
        }

        //返回对象
        PayResponse response = new PayResponse();
        response.setIsOrderPaySucess(false);
        response.setIsPayPlatfrom(false);

        //订单
        SaleOrder order = getOrderBySo(sale_no);
        if (order == null) {
            // 订单不存在
            logger.error("支付的订单不存在： sale_no=" + sale_no);
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_PAYERROR);
        }

        // 判断订单状态是否可支付   (支付条件：   订单状态：创建    支付状态： 未支付，部分支付)
        String payAction = getPayActionCode(order.getStatus(), order.getPayType(), order.getOrderCategory(), order.getPayStatus());
        if (payAction.equals("CannotPay")) {
            logger.error(String.format("支付的订单不可支付： sale_no={0} status={1} payStatus={2}", sale_no, order.getStatus(), order.getPayStatus()));
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_CANNOTPAY);
        }

        //货到付款不能去支付
        if (order.getPayType().equals("货到付款")) {
            logger.error(String.format("货到付款的订单不可支付： sale_no={0} status={1} payStatus={2}", sale_no, order.getStatus(), order.getPayStatus()));
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_CANNOTPAY, "货到付款订单不可以支付");
        }
        //特殊订单不能使用余额支付（团购订单，市场部拉新订单，虚拟商品订单）
        if(is_balance){
            //检验
            if(order.getOrderCategory().equals("团购订单")||order.getOrderCategory().equals("市场部拉新订单")||order.getOrderCategory().equals("虚拟商品订单")){
                logger.warn("this order can't use balance to pay (sale_no:" + sale_no +")" + order.getOrderCategory());
                throw new ServiceException(OrderErrorCodes.errorCodes_PAY_PAYERROR);
            }
        }

        //余额支付
        if (is_balance) {
            //region 余额支付
            AccountBalance accountBalance = null;
            try {
                RpcContext.getContext().setAttachment(CommonParameter.userId, customer_id);
                accountBalance = memberService.getBalance();
            } catch (Exception ex) {
                logger.warn("userinfo cannot found in pagepa: customer:" + customer_id);
                throw new ServiceException(OrderErrorCodes.errorCodes_USERBALANCE_NOT_FOUND);
            }

            //待支付金额
            double waitPayAmount = order.getTotalAmount().subtract(order.getPaidAmount()).doubleValue();
            //如果待支付金额大于余额，支付金额就是余额
            if (waitPayAmount > accountBalance.balance) {
                waitPayAmount = accountBalance.balance;
            }

            if (waitPayAmount <= 0) {
                throw new ServiceException(OrderErrorCodes.errorCodes_PAY_FAILURE);
            }

            //插入支付记录请求表
            SaleOrderPay orderPay = new SaleOrderPay();
            orderPay.setSoNo(order.getSaleNo());
            orderPay.setPayChannel("Balance");
            orderPay.setAmount(BigDecimal.valueOf(0));
            orderPay.setStatus(PayStatus.Create.value());
            orderPay.setCreatedBy("system");
            orderPay.setCreatedTime(new Date());
            orderPay.setModifiedBy("system");
            orderPay.setModifiedTime(new Date());
            saleOrderPayLogic.insertSelective(orderPay);

            //扣除用户余额
            AccountDebuctInfo accountDebuct = null;
            try {
                RpcContext.getContext().setAttachment(CommonParameter.userId, customer_id);
                accountDebuct = memberService.deduct(order.getSaleNo(), order.getId(), waitPayAmount, orderPay.getId().toString());
            } catch (Exception ex) {
                logger.error("【会员服务|扣除余额】（失败）");
                logger.error(ex);
                throw new ServiceException(OrderErrorCodes.errorCodes_USER_DEDUCT_ERROR, ex.getMessage());
            }

            double accountPaidAmount = 0;
            if (accountDebuct != null && (accountDebuct.getCode().equals("0000") || accountDebuct.getCode().equals("9999"))) {
                accountPaidAmount = accountDebuct.getAmount();
            } else {
                logger.warn("余额支付失败：sale_no=" + sale_no + "   支付结果=" + "");
                throw new ServiceException(OrderErrorCodes.errorCodes_PAY_FAILURE);
            }

            SaleOrderPay orderPay_update = saleOrderPayLogic.get(orderPay.getId());
            //成功后修改支付记录
            orderPay_update.setAmount(BigDecimal.valueOf(accountPaidAmount));
            orderPay_update.setStatus(PayStatus.Success.value());
            saleOrderPayLogic.update(orderPay_update);

            order.setPaidAmount(order.getPaidAmount().add(BigDecimal.valueOf(accountPaidAmount)));
            if (order.getPaidAmount().compareTo(order.getTotalAmount()) >= 0) {
                //如果全部支付
                order.setPayStatus(com.ulife.order.service.enumeration.SaleOrderPayStatus.Paid.value());
                order.setPayChannel("Balance");
                order.setConfirmTime(now);
                order.setModifiedBy("system");
                order.setModifiedTime(now);
                if (order.getOrderCategory().equals("虚拟商品订单")) {
                    order.setStatus(SaleOrderStatus.Finished.value());
                } else {
                    order.setStatus(SaleOrderStatus.Confirmed.value());
                }

                int saleorder_update = saleOrderLogic.updateSelective(order);
                //支付记录
                if (saleorder_update <= 0) {
                    throw new ServiceException(OrderErrorCodes.errorCodes_PAY_FAILURE);
                }
                response.setIsOrderPaySucess(true);
                //团购订单通知
                sendGroupMsg(order,1);
                //订单成功发券
                String src = order.getSrc()==null?"": order.getSrc();
                sendOrderedCoupon(customer_id,order.getSaleNo(),order.getOrderCategory(),order.getTotalAmount().toString(),order.getTerminal().toString(),src);

                //如果是虚拟商品订单则需要给用户绑定券
                if(order.getOrderCategory().equals("虚拟商品订单"))
                {
                    bindPromotionForVirtual(order.getSaleNo(),_terminal,customer_id);
                }
                //
                try{
                    //支付成功
                    //订单支付回调-银行满减-银行支付优惠使用状态更新
                    PayResultPromotionUpdateStatus(order.getSaleNo(),orderPay.getId(),order.getCustomerId());
                }catch (ServiceException sex){
                    logger.error(sex.toString());
                }

                return response;

            } else {
                //如果部分支付
                order.setPayStatus(com.ulife.order.service.enumeration.SaleOrderPayStatus.PartialPay.value());
                order.setModifiedBy("system");
                order.setModifiedTime(now);
                int saleorder_update = saleOrderLogic.updateSelective(order);

                //支付记录
                if (saleorder_update <= 0) {
                    throw new ServiceException(OrderErrorCodes.errorCodes_PAY_FAILURE);
                }
            }
            //endregion
        }

        if (channel_no == null || channel_no.isEmpty()) {
            logger.warn("支付方式不存在： sale_no=" + sale_no);
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_PAYERROR);
        }

        //region 团购订单只能用可以退款的方式支付
        if(order.getOrderCategory().equals("团购订单"))
        {
            String[] refundChanelNos = refundChanelNo.split(",");
            List<String> refundChanelNo_arr = Arrays.asList(refundChanelNos);
            if(!refundChanelNo_arr.contains(channel_no))
            {
                //refundChanelNo
                String content = " saleOrder:\r\n"
                        + Json.toJson(order)+"\r\n"
                        + "channel_no:\r\n"
                        + channel_no;
                sendYJEmail("(团购支付方式不正确)",content);
                throw new ServiceException(OrderErrorCodes.errorCodes_PAY_CANNOTPAY,"支付方式不可用");
            }
        }
        //endregion

        // 传递的请求参数
        PayRequest payRequest = getPayRequst(order, channel_no, card_type, app_id, client_ip, openid, return_url,customer_id,_terminal);
        if (payRequest == null) {
            logger.error(String.format("支付请求构建失败： sale_no={0} channel_no={1} card_type={2}", sale_no, channel_no, card_type));
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_PAYERROR);
        }
        //platform
        payRequest.setPlatform(platform);

        response.setIsOrderPaySucess(false);
        response.setIsPayPlatfrom(true);
        response.setPayRequest(payRequest);
        response.setPayUrl(payUrl);

        //如果是app 去支付平台获取数据
        if (app_id.equals("1004") || app_id.equals("1005")) {
            List<NameValuePair> list = new ArrayList<NameValuePair>();
            list.add(new BasicNameValuePair("para", Json.toJson(response.getPayRequest())));
            logger.info("[支付|app请求支付平台： 请求信息]=" + Json.toJson(response.getPayRequest()));
            String appStr = doPost(response.getPayUrl(), "utf-8", list);
            logger.info("[支付|app请求支付平台： 返回信息]=" + appStr);
            response.setAppPayInfo(appStr);
        }

        //如果是微信PC|wap 去支付平台获取数据
        if (channel_no.equals("07") || channel_no.equals("")) {
            List<NameValuePair> list = new ArrayList<NameValuePair>();
            list.add(new BasicNameValuePair("para", Json.toJson(response.getPayRequest())));
            logger.info("[支付|微信请求支付平台： 请求信息]=" + Json.toJson(response.getPayRequest()));
            String appStr = doPost(response.getPayUrl(), "utf-8", list);
            logger.info("[支付|微信请求支付平台： 返回信息]=" + appStr);
            response.setWeixinInfo(appStr);
        }

        logger.info("支付平台相应：" + Json.toJson(response));
        return response;
    }

    private String doPost(String address, String encoding, List<NameValuePair> param) {
        String resStr = "";

        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建参数队列
        List<NameValuePair> formparams = param;

        UrlEncodedFormEntity uefEntity = null;
        CloseableHttpResponse httpResponse = null;
        try {
            // 创建httppost
            HttpPost httpPost = new HttpPost(address);

            uefEntity = new UrlEncodedFormEntity(formparams, encoding);
            httpPost.setEntity(uefEntity);

            // 执行post请求
            httpResponse = httpClient.execute(httpPost);
            // 取得响应结果
            HttpEntity entity = httpResponse.getEntity();
            if (entity != null) {
                // 取得响应消息的json串
                resStr = EntityUtils.toString(entity, encoding);
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (httpResponse != null) {
                try {
                    httpResponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return resStr;
    }

    /**
     * 构建支付请求信息
     *
     * @return
     */
    private PayRequest getPayRequst(SaleOrder order, String channel_no, String card_type, String app_id, String client_ip, String openid, String return_url,String customer_id,String _terminal) throws ServiceException {

        String trade_type = "";//NATIVE  JSAPI APP
        String app_key = "";
        String pay_request_type = ""; //农行请求  1,PC 2,WAP

        //appkey 暂时写死
        if (app_id.equals("2001")) {
            trade_type = "NATIVE";
            pay_request_type = "1";
        } else if (app_id.equals("1001") || app_id.equals("1006")) {
            trade_type = "JSAPI";
            pay_request_type = "2";
        } else if (app_id.equals("1004")) {
            trade_type = "APP";
        } else if (app_id.equals("1005")) {
            trade_type = "APP";
        }

        app_key = getAppKey(app_id);

        if (order == null) {
            return null;
        }
        /*
        if (card_type == null || card_type.isEmpty()) {
            //card_type   1,借记卡 2，贷记卡   目前只有农行有用
            //如果没传，默认为1
            card_type = "1";
        }*/
        //固定
        card_type = "2";

        //region 插入支付记录请求表
        SaleOrderPay orderPay = new SaleOrderPay();
        String channelName="";
        orderPay.setSoNo(order.getSaleNo());
        try {
            channelName=memberService.getPayChannelByNo(channel_no).getChannelName();
            orderPay.setPayChannel(channelName);//todo 写channel_name 从接口common.paytype里面取
        } catch (Exception ex) {
            logger.error(String.format("[会员服务|获取支付名称报错] msg+", ex.getMessage()));
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_PAYERROR, "[会员服务|获取支付名称报错]" + ex.getMessage());
        }

        PromoRules rules=GetBankPromotionRules(channel_no,order,customer_id,_terminal);
        if (rules != null) {
            orderPay.setAmount(order.getTotalAmount().subtract(order.getPaidAmount()).subtract(new BigDecimal(rules.getPreferential())));
        } else {
            orderPay.setAmount(order.getTotalAmount().subtract(order.getPaidAmount()));
        }
        orderPay.setStatus(PayStatus.Create.value());

        orderPay.setCreatedBy("system");
        orderPay.setCreatedTime(new Date());
        orderPay.setModifiedBy("system");
        orderPay.setModifiedTime(new Date());
        int SerialNumber = saleOrderPayLogic.insertSelective(orderPay);
        if (SerialNumber == 0) {
            logger.error(String.format("支付请求构建失败，插入支付记录失败  saleno= ", order.getSaleNo()));
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_PAYERROR);
        }else
        {
            if(rules!=null) {
                SaleOrderPay pay = new SaleOrderPay();
                pay.setSoNo(order.getSaleNo());
                pay.setPayChannel(channelName);
                pay.setAmount(new BigDecimal(rules.getPreferential()));
                pay.setStatus(PayStatus.Create.value());
                pay.setCreatedBy("system");
                pay.setCreatedTime(new Date());
                pay.setModifiedBy("system");
                pay.setModifiedTime(new Date());
                pay.setPayId(orderPay.getId());
                pay.setBankPromotionId(rules.getId());
                int _serialNumber = saleOrderPayLogic.insertSelective(pay);
                if (_serialNumber == 0) {
                    logger.error(String.format("支付请求构建失败，插入银行满减优惠记录失败  saleno= ", order.getSaleNo()));
                    throw new ServiceException(OrderErrorCodes.errorCodes_PAY_PAYERROR);
                }
            }
        }
        //endregion

        //这里更改订单channel_no没什么意义，等支付回调时更新
        //order.setPayChannel(channel_no);
        PayRequest payRequest = new PayRequest();
        // 应用系统编号
        payRequest.setMerchantId(app_id);
        // 支付渠道编号
        payRequest.setChannelNo(channel_no);
        // 订单号d
        payRequest.setOrderId(order.getSaleNo());
        //SerialNumber
        payRequest.setSerialNumber(orderPay.getId().toString());
        // 金额
        payRequest.setAmount(Double.parseDouble(orderPay.getAmount().toString()));
        //IP
        payRequest.setClientIP(client_ip);
        //ordertype
        payRequest.setOrderType(2); // 1销售  2充值   实际 2值得是通知支付结果
        //orderDetailUrl
        payRequest.setOrderDetailUrl(payOrderDetailUrl);
        payRequest.setReturnUrl(return_url == null ? "" : return_url);
        payRequest.setDescription(payDescription);
        payRequest.setCallBackUrl(payCallbackUrl);
        //#微信
        //NATIVE  JSAPI APP
        payRequest.setTradeType(trade_type);
        // #农行
        //pay_request_type 1,PC 2,WAP
        payRequest.setPayRequestType(pay_request_type);
        payRequest.setCardType(card_type);
        payRequest.setErrorPage(payErrorPage);
        //如果是翼支付，需要支付手机号
        if (channel_no.equals("19")) {
            SaleOrderShip saleOrderShip = getShipBySo(order.getSaleNo());
            if (saleOrderShip != null) {
                payRequest.setMobileNo(saleOrderShip.getMobile());
            }
        }
        payRequest.setOpenid(openid);

        // 请求签名
        StringBuffer signature = new StringBuffer();
        signature
                .append("AMOUNT").append("=").append(new DecimalFormat("####0.00").format(payRequest.getAmount())).append("&")
                .append("CALLBACKURL").append("=").append(payRequest.getCallBackUrl()).append("&")
                .append("CHANNELNO").append("=").append(payRequest.getChannelNo()).append("&")
                .append("DESCRIPTION").append("=").append(payRequest.getDescription()).append("&")
                .append("MERCHANTID").append("=").append(payRequest.getMerchantId()).append("&")
                .append("ORDERID").append("=").append(payRequest.getOrderId()).append("&")
                .append("RETURNURL").append("=").append(payRequest.getReturnUrl()).append("&")
                .append("SERIALNUMBER").append("=").append(payRequest.getSerialNumber()).append("&")
                .append("KEY").append("=").append(app_key);
        payRequest.setSignature(DigestUtils.md5Hex(signature.toString()));

        logger.info("构建支付签名信息：" + signature + "   sign=" + payRequest.getSignature());
        return payRequest;
    }

    /***
     * 根据支付渠道调用[优惠服务]获取银行优惠规则信息
     * @param channel_no
     * @param order
     * @return
     * @throws ServiceException
     */
    private  PromoRules GetBankPromotionRules(String channel_no,SaleOrder order,String _customer_id,String _terminal) throws ServiceException
    {
        RpcContext.getContext().setAttachment(CommonParameter.userId, _customer_id);
        RpcContext.getContext().setAttachment(ExtendParameter.terminal,_terminal);
        try{
            String content = " GetBankPromotionRules:saleOrder:\r\n"+ Json.toJson(order)+"\r\n" + "channel_no:\r\n"+ channel_no+"\r\n" + "userId:\r\n" + _customer_id+"\r\n"  + "terminal:\r\n" + _terminal+"\r\n";
            logger.info("[优惠服务|获取银行满减优惠规则] 传递参数:"+ content);
            PromoRules promoRules= promoService.promoPayCalculate(channel_no,order.getSaleNo(),order.getTotalAmount().subtract(order.getPaidAmount()).doubleValue());
            if(promoRules!=null) {
                logger.info("[优惠服务|获取银行满减优惠规则] 返回数据:" + " PromoRules:\r\n" + Json.toJson(promoRules) + "\r\n");
            }
            else{
                logger.info("[优惠服务|获取银行满减优惠规则] 返回数据为空!" + " PromoRules is Null.\r\n");
            }
            return  promoRules;
        }catch (Exception ex)
        {
            logger.error(String.format("[优惠服务|获取银行满减优惠规则报错] msg+", ex.getMessage()));
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_PAYERROR, "[优惠服务|获取银行满减优惠规则报错]" + ex.getMessage());
        }
    }
    /**
     * 支付结果
     *
     * @param amount
     * @param sale_no
     * @param pay_id
     * @param tx_serial_number
     * @param BankSerialNumber
     * @param order_type
     * @param merchant_id
     * @return
     * @throws ServiceException
     */
    @Override
    @Transactional
    public ResponseMessage payResult(@ApiParameter(required = true, name = "amount", desc = "金额") double amount,
                                     @ApiParameter(required = true, name = "sale_no", desc = "订单号") String sale_no,
                                     @ApiParameter(required = true, name = "pay_id", desc = "支付记录ID") long pay_id,
                                     @ApiParameter(required = true, name = "TxSerialNumber", desc = "支付序列号") String tx_serial_number,
                                     @ApiParameter(required = false, name = "BankSerialNumber", desc = "银行支付序列号") String BankSerialNumber,
                                     @ApiParameter(required = true, name = "order_type", desc = "支付类型") String order_type,
                                     @ApiParameter(required = true, name = "merchant_id", desc = "平台ID") String merchant_id) throws ServiceException {

        ResponseMessage rtn = new ResponseMessage();
        Date now = new Date();
        rtn.isSuccess = false;

        //region  数据验证
        //验证支付通知信息
        if (amount == 0 || Strings.isNullOrEmpty(sale_no) || pay_id < 1) {
            rtn.setMessage("支付通知信息参数验证失败");
            logger.warn("OrderService.payResult sale_no=" + sale_no + ", pay_id=" + pay_id + ", amount:" + amount + " 支付通知信息参数验证失败");
            return rtn;
        }
        //订单是否存在
        SaleOrder order = getOrderBySo(sale_no);
        String _terminal = order.getTerminal();
        String customer_id = order.getCustomerId().toString();
        if (order == null) {
            rtn.setMessage("订单号不存在");
            logger.warn("OrderService.payResult sale_no = " + sale_no + " 订单不存在");
            return rtn;
        }
        //支付记录是否存在
        SaleOrderPay orderPay = saleOrderPayLogic.get(pay_id);
        if (orderPay == null) {
            rtn.setMessage("OrderService.payResult pay_id =" + pay_id + "支付记录不存在");
            return rtn;
        }
        //是否重复处理 (同一个支付处理多次，不是重复支付)
        if (orderPay.getStatus().equals(PayStatus.Success.value())) {
            rtn.isSuccess = true;
            rtn.setMessage("处理支付结果时，重复处理支付结果；RequestSerialNumber = " + pay_id);
            return rtn;
        }
        //endregion

        /*
        * 新逻辑
        * 1.记录支付结果
        * 2.重复支付(多余的支付，订单显示已经支付)或者订单已经取消（订单状态为 已取消）
        * 3.更新订单支付状态，更新订单状态
        * 4.订单支付成功之后处理事件
        * */
        //记录支付结果
        orderPay.setBankSerialNo(BankSerialNumber);
        orderPay.setTxSerialNumber(tx_serial_number);
        orderPay.setStatus(PayStatus.Success.value());
        orderPay.setModifiedBy("system");
        orderPay.setModifiedTime(now);
        if (saleOrderPayLogic.updateSelective(orderPay) != 1) {
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_FAILURE_UPDATE_SALEORDERPAY_ERROR);
        }
        //重复支付(多余的支付，订单显示已经支付)或者订单已经取消（订单状态为 已取消）
        if (order.getPayStatus().equals(SaleOrderPayStatus.Paid.value())
                || order.getStatus().equals(SaleOrderStatus.Cancel.value())) {
            try {
                orderRefund.createSoRefundBill(orderPay, null, null, null,9999);
            } catch (Exception ex) {
                throw new ServiceException(OrderErrorCodes.errorCodes_PAY_FAILURE_CREATE_SOREFUNDBILL_ERROR);
            }
            return rtn;
        }

        //添加银行支付优惠记录更新 + 支付金额更新
        SaleOrderPayCriteria saleOrderPayCriteria = new SaleOrderPayCriteria();
        saleOrderPayCriteria.createCriteria()
                .andPayIdEqualTo(pay_id)
                .andBankPromotionIdGreaterThan(0L)
                .andStatusEqualTo(PayStatus.Create.value());
        List<SaleOrderPay> promotions = saleOrderPayLogic.list(saleOrderPayCriteria);
        if (promotions != null && promotions.size() > 0) {
            SaleOrderPay promotion = promotions.get(0);
            promotion.setStatus(PayStatus.Success.value());
            promotion.setModifiedBy("system");
            promotion.setModifiedTime(now);
            saleOrderPayLogic.updateSelective(promotion);
            amount = amount + promotion.getAmount().doubleValue();

            try {
                Results results = null;
                RpcContext.getContext().setAttachment(CommonParameter.userId,customer_id);
                results = promoService.promoPayLogUpdateStatus(promotion.getBankPromotionId(), promotion.getSoNo(), 1);
                if (results == null || !results.success) {
                    throw new Exception(results == null ? "返回结果为：NULL" : results.getMessage());
                }else{
                    logger.info("[优惠服务|银行支付优惠使用状态更新]:result:success,message:".concat(results.getMessage()));
                }
            } catch (Exception ex) {
                logger.error("[优惠服务|银行支付优惠使用状态更新失败]" + ex.getMessage());
                throw new ServiceException(OrderErrorCodes.errorCodes_PAY_FAILURE, "[优惠服务|银行支付优惠使用状态更新失败]" + ex.getMessage());
            }
        }

        //更新订单已支付金额
        BigDecimal paidAmount = order.getPaidAmount().add(BigDecimal.valueOf(amount));
        order.setPaidAmount(paidAmount);
        if (paidAmount.doubleValue() >= order.getTotalAmount().doubleValue()) {
            order.setPayStatus(SaleOrderPayStatus.Paid.value());
            order.setStatus(SaleOrderStatus.Confirmed.value());
        } else {
            order.setPayStatus(SaleOrderPayStatus.PartialPay.value());
        }
        //虚拟商品订单 处理逻辑
        if (order.getOrderCategory().equals("虚拟商品订单") && order.getPayStatus().equals(SaleOrderPayStatus.Paid.value()))
            order.setStatus(SaleOrderStatus.Finished.value());

        //更新订单信息
        order.setConfirmTime(now);
        order.setPayChannel(orderPay.getPayChannel());
        order.setModifiedBy("system");
        order.setModifiedTime(now);
        if (saleOrderLogic.updateSelective(order) != 1) {
            throw new ServiceException(OrderErrorCodes.errorCodes_PAY_FAILURE_UPDATE_SALEORDER_ERROR);
        }

        //订单支付成功之后 处理事件
        if (order.getStatus() == SaleOrderStatus.Finished.value()
                || order.getStatus() == SaleOrderStatus.Confirmed.value()) {
            //订单支付成功通知发券
            String src = order.getSrc() == null ? "" : order.getSrc();
            sendOrderedCoupon(order.getCustomerId().toString(), order.getSaleNo(), order.getOrderCategory(),
                    order.getTotalAmount().toString(), order.getTerminal().toString(), src);
            //团购通知
            sendGroupMsg(order, 1);

            //如果是虚拟商品订单则需要给用户绑定券
            if (order.getOrderCategory().equals("虚拟商品订单")) {
                bindPromotionForVirtual(order.getSaleNo(), _terminal, customer_id);
            }

            try{
                //支付成功
                //订单支付回调-银行满减-银行支付优惠使用状态更新
                PayResultPromotionUpdateStatus(order.getSaleNo(),pay_id,order.getCustomerId());
            }catch (ServiceException sex){
                logger.error(sex.toString());
            }
            rtn.isSuccess = true;
        }
        return rtn;
    }

    /**
     * 订单成功通知发券
     *
     * @param customerId
     * @param sale_no
     * @param total
     * @param terminal
     */
    private void sendOrderedCoupon(String customerId, String sale_no,String orderType, String total, String terminal, String source) {
        try {
            //首单
            CustomerFirstSale customerFirstSale =  getFristOrder(Long.parseLong(customerId));

            boolean isFirst = false;
            if (customerFirstSale!=null&&customerFirstSale.getSoNo().equals(sale_no))
            {
                isFirst =true;
            }

            Map<String, Object> data = Maps.newHashMap();
            data.put("customerId", customerId);
            data.put("order_no", sale_no);
            data.put("total_amount", total);
            data.put("terminal", terminal);
            data.put("order_type",orderType);
            data.put("src", source);
            data.put("fast_order", isFirst ? 1 : 0);
            RedisEvent event = RedisEvent.ordered(data);
            redisTemplate.convertAndSend(RedisEvent.Channels.COUPON, event);

            logger.info("[订单支付成功后发券] 券消息信息：" + Json.toJson(data));
        } catch (Exception ex) {
            logger.error("[订单成功通知发券失败]");
            logger.error(ex);
        }
    }
    /**
     * 团购通知订单 （现在是所有订单都通知，因为抽奖也用到）
     *
     * @param order
     */
    private void sendGroupMsg(SaleOrder order, Integer code) throws ServiceException {
        //code code:1:支付成功，0取消
        //if (order.getOrderCategory().equals("团购订单"))
        {
            try {
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("orderNo", order.getSaleNo());
                map.put("code", code);
                map.put("customerId",order.getCustomerId());
                map.put("subAmount",order.getSubAmount().doubleValue());
                map.put("totalAmount",order.getTotalAmount().doubleValue());
                messageSender.sendMessage(map);
            } catch (Exception ex) {
                logger.error("团购通知失败，报错");
                logger.error(ex);
            }
            logger.info("团购订单成功通知： saleno:" + order.getSaleNo());
        }
    }

    private String getAppKey(String app_id) {
        switch (app_id) {
            case "2001":
                return "ulife2001web";
            case "1001":
                return "ulife2001wap";
            case "1004":
                return "ulife1004android";
            case "1005":
                return "ulife1005ios";
            case "1006":
                return "ulife1005h5";
            default:
                return "";
        }
    }

    /**
     * 获取主订单列表
     *
     * @param status
     * @param start_date
     * @param end_date
     * @param page
     * @param rows
     * @return
     * @throws ServiceException
     */
    @Override
    public SaleOrderListInfo list(
            @ApiParameter(required = false, name = "statusValue", desc = "订单状态") String status,
            @ApiParameter(required = false, name = "start_date", desc = "订单开始时间") long start_date,
            @ApiParameter(required = false, name = "end_date", desc = "订单开始时间") long end_date,
            @ApiParameter(required = false, name = "page", desc = "第n页") int page,
            @ApiParameter(required = false, name = "rows", desc = "分页条数") int rows) throws ServiceException {

        SaleOrderListInfo orderListInfo = new SaleOrderListInfo();

        //公共参数
        String customerId = RpcContext.getContext().getAttachment(CommonParameter.userId);
        long customer_id = Long.parseLong(customerId);

        //分页默认值
        if (page == 0) {
            page = 1;
        }
        if (rows == 0) {
            rows = 20;
        }

        //查询订单信息

        //总条数
        String countExtendSqlStr = ExtendOrderSql(customerId, status, start_date, end_date, "", 0, 0);
        int count = saleOrderLogic.countExtendSql(new SQLAdapter(countExtendSqlStr));


        //订单列表
        int startIndex = (Math.max(1, page) - 1) * rows;
        String listExtendSqlStr = ExtendOrderSql(customerId, status, start_date, end_date, "order_time desc", startIndex, rows);
        List<SaleOrder> orderList = saleOrderLogic.listExtendSql(new SQLAdapter(listExtendSqlStr));

        //没有则返回
        if (orderList.size() == 0) {
            return orderListInfo;
        }

        //订单列表信息
        List<SaleOrderInfo> ordersInfo = orderInfoListMapping(orderList);

        //订单列表信息构建
        for (SaleOrderInfo orderInfo : ordersInfo) {
            if (orderInfo == null) {
                continue;
            }

            //查询地址信息
            AddressInfo addressInfo = null;
            if (!orderInfo.getOrderCategory().equals("虚拟商品订单")) {
                addressInfo = getAddressInfoBySo(orderInfo.getSaleNo());
                orderInfo.setAddress(addressInfo);
            }

            //订单待支付金额
            orderInfo.setWaitPaidAmount(orderInfo.getTotalAmount() - orderInfo.getPaidAmount());

            //订单包裹数量    //TODO 统计条数还可以再优化
            ShipmentOrderItemCriteria shipmentOrderItemCriteria = new ShipmentOrderItemCriteria();
            shipmentOrderItemCriteria.createCriteria().andSoNoEqualTo(orderInfo.getSaleNo());
            List<ShipmentOrderItem> shipmentOrderItems = shipmentOrderItemLogic.list(shipmentOrderItemCriteria);
            List<String> shipments = new ArrayList<String>();
            for (ShipmentOrderItem shipmentOrderItem : shipmentOrderItems) {
                if (!shipments.contains(shipmentOrderItem.getShipOrderNo())) {
                    shipments.add(shipmentOrderItem.getShipOrderNo());
                }
            }
            int shipmentCount = shipments.size();
            orderInfo.setShipmentCount(shipmentCount);

            //订单商品
            List<ItemInfo> items = getOrderItemInfoList(orderInfo.getSaleNo());
            if (items != null) {
                orderInfo.setItems(items);
                //订单商品个数
                orderInfo.setProductCount(items.size());
            }

            //订单支付操作code
            orderInfo.setPayActionCode(getPayActionCode(orderInfo.getStatus(), orderInfo.getPayType(), orderInfo.getOrderCategory(), orderInfo.getPayStatus()));
            //订单取消操作code
            orderInfo.setCancelActionCode(getCancelActionCode(orderInfo.getStatus(), orderInfo.getPayType(), "", orderInfo.getOrderCategory(), orderInfo.getPayStatus()));
        }

        orderListInfo.setCount(count);
        orderListInfo.setOrders(ordersInfo);
        return orderListInfo;
    }

    @Override
    public RawString yqf(@ApiParameter(required = false, name = "orderNo", desc = "订单号", defaultValue = "") String orderNo,
                                @ApiParameter(required = false, name = "cid", desc = "活动ID", defaultValue = "") String cid,
                                @ApiParameter(required = false, name = "updateStartTime", desc = "订单更新开始时间") long updateStartTime,
                                @ApiParameter(required = false, name = "updateEndTime", desc = "订单更新结束时间") long updateEndTime,
                                @ApiParameter(required = false, name = "orderStartTime", desc = "订单生成开始时间") long orderStartTime,
                                @ApiParameter(required = false, name = "orderEndTime", desc = "订单生成结束时间") long orderEndTime
    ) throws ServiceException {
        RawString rtn = new RawString();
        if (cid == null || cid.isEmpty()) throw new ServiceException(OrderErrorCodes.getErrorCodes_ORDER_INPUT_ERROR);
        String source = "emar|" + cid;
        if (orderNo != null && !orderNo.isEmpty()) {
            SaleOrderInfo saleOrderInfo = detail(orderNo);
            rtn.value = JsonUtils.obj2Json(yqf.get(saleOrderInfo, source));
            return  rtn;
        }
        long gap = 0;
        long hour48 = 48 * 60 * 60 * 1000;//最大范围48个小时
        if (orderStartTime > 0 && orderEndTime > 0) {
            gap = orderEndTime - orderStartTime;
            if (gap > hour48) throw new ServiceException(OrderErrorCodes.getErrorCodes_ORDER_LIST_RANGE_ERROR);
            rtn.value= JsonUtils.obj2Json(yqf.listByOrderTime(orderStartTime, orderEndTime, source));
            return  rtn;
        }
        if (updateStartTime > 0 && updateEndTime > 0) {
            gap = updateEndTime - updateStartTime;
            if (gap > hour48) throw new ServiceException(OrderErrorCodes.getErrorCodes_ORDER_LIST_RANGE_ERROR);
            rtn.value = JsonUtils.obj2Json(yqf.listByUpdateTime(updateStartTime, updateEndTime, source));
            return rtn;
        }
        throw new ServiceException(OrderErrorCodes.getErrorCodes_ORDER_INPUT_ERROR);
    }

    /**
     * 订单list映射
     *
     * @param orderlist
     * @return
     */
    private List<SaleOrderInfo> orderInfoListMapping(List<SaleOrder> orderlist) {
        List<SaleOrderInfo> list = null;
        if (orderlist == null || orderlist.size() == 0) {
            return list;
        }

        list = new ArrayList<SaleOrderInfo>();

        for (SaleOrder saleOrder : orderlist) {
            SaleOrderInfo orderInfo = orderInfoMapping(saleOrder);
            if (orderInfo != null) {
                list.add(orderInfo);
            }
        }
        return list;
    }

    /**
     * 获取主订单明细
     *
     * @param sale_no
     * @return
     * @throws ServiceException
     */
    @Override
    public SaleOrderInfo detail(@ApiParameter(required = true, name = "sale_no", desc = "订单号") String sale_no) throws ServiceException {

        if (sale_no == null || sale_no.isEmpty()) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }
        SaleOrderInfo orderInfo = getOrderInfoBySo(sale_no);
        //查询订单信息
        if (orderInfo == null) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }

        //订单支付操作code
        orderInfo.setPayActionCode(getPayActionCode(orderInfo.getStatus(), orderInfo.getPayType(), orderInfo.getOrderCategory(), orderInfo.getPayStatus()));
        //订单取消操作code
        orderInfo.setCancelActionCode(getCancelActionCode(orderInfo.getStatus(), orderInfo.getPayType(), "", orderInfo.getOrderCategory(), orderInfo.getPayStatus()));

        //如果可支付，获取支付信息
        if (!orderInfo.getPayActionCode().equals("CannotPay")) {
            //待支付金额
            orderInfo.setWaitPaidAmount(orderInfo.getTotalAmount() - orderInfo.getPaidAmount());

            //待支付时算订单支付倒计时
            Calendar dar = Calendar.getInstance();
            dar.setTime(new Date(orderInfo.getOrderTime()));
            dar.add(java.util.Calendar.HOUR_OF_DAY, 2);
            Date endDate = dar.getTime();
            long exceedtime = dar.getTime().getTime() - new Date().getTime();
            orderInfo.setExceedTime(exceedtime > 0 ? exceedtime : 0);
        }

        //查询地址信息
        AddressInfo addressInfo = null;
        if (!orderInfo.getOrderCategory().equals("虚拟商品订单")) {
            addressInfo = getAddressInfoBySo(sale_no);
            orderInfo.setAddress(addressInfo);
        }

        //查询所有包裹信息
        ShipmentOrderItemCriteria shipmentOrderItemCriteria = new ShipmentOrderItemCriteria();
        ShipmentOrderItemCriteria.Criteria shipmentOrderItem_criteria = shipmentOrderItemCriteria.createCriteria();
        shipmentOrderItem_criteria.andSoNoEqualTo(orderInfo.getSaleNo());
        List<ShipmentOrderItem> shipmentOrderItems = shipmentOrderItemLogic.list(shipmentOrderItemCriteria);

        //订单中所有商品
        List<ItemInfo> itemInfoList = getOrderItemInfoList(sale_no);
        //虚拟商品
        List<VirtualProductInfo> virtualProductInfoList = new ArrayList<VirtualProductInfo>();
        if (orderInfo.getOrderCategory().equals("虚拟商品订单")) {
                for (ItemInfo inf : itemInfoList) {
                    VirtualProductInfo vinfo = new VirtualProductInfo();
                    vinfo = getPromoByPublicWesen(inf.getPublicWesen(),inf.getPromoId(),orderInfo.getPayStatus());
                    if (vinfo != null ) {
                        virtualProductInfoList.add(vinfo);
                    }
                }
                orderInfo.setVirtualProductInfos(virtualProductInfoList);
                return orderInfo;
        }


        //region 处理订单商品的分组信息
        //如果没有发货单，就取item
        //查询商品信息
        //self
        ItemGroupInfo group_self = new ItemGroupInfo();//self
        group_self.setMode("self");//自营
        group_self.setItems(new ArrayList<ItemInfo>());
        //consignation
        ItemGroupInfo group_consignation = new ItemGroupInfo();
        group_consignation.setMode("consignation"); //代销
        group_consignation.setItems(new ArrayList<ItemInfo>());

        for (ItemInfo itemInfo : itemInfoList) {
            if (itemInfo.getItemForm().toUpperCase().equals("SELF")) {
                group_self.getItems().add(itemInfo);
            } else if (itemInfo.getItemForm().toUpperCase().equals("CONSIGNATION")) {
                group_consignation.getItems().add(itemInfo);
            }
        }

        orderInfo.setGroups(new ArrayList<ItemGroupInfo>());
        orderInfo.getGroups().add(group_self);
        orderInfo.getGroups().add(group_consignation);
        //endregion

        if (shipmentOrderItems != null && shipmentOrderItems.size() > 0) {
            //先做个一个订单所有商品的map，方便下面找商品
            Map<Long, ItemInfo> order_item_map = new HashMap<Long, ItemInfo>();
            for (ItemInfo itemInfo : itemInfoList) {
                order_item_map.put(itemInfo.getItemId(), itemInfo);
            }

            //未发货商品map   开始是所有商品，循环包裹商品时，排除。 剩余就是未发货商品
            Map<Long, ItemInfo> not_ship_item_map = new HashMap<Long, ItemInfo>();
            not_ship_item_map.putAll(order_item_map);

            //第一部分   有发货单，就组装包裹信息/////////////////////////////////////////////////////////////
            //包裹的map，下面去组装
            Map<String, ShipmentInfo> shipment_map = new HashMap<String, ShipmentInfo>();

            for (ShipmentOrderItem shipmentOrderItem : shipmentOrderItems) {
                //循环所有包裹的商品
                //1. 如果包裹map没有此包裹，就创建包裹，并填充商品
                //2. 如果包裹map有此包裹，填充商品

                //排除发货包裹商品
                not_ship_item_map.remove(shipmentOrderItem.getItemId());

                if (!shipment_map.containsKey(shipmentOrderItem.getShipOrderNo())) {
                    //如果不存在包裹，创建包裹。

                    //创建包裹
                    ShipmentInfo shipmentInfo = new ShipmentInfo();
                    shipmentInfo.setSaleNo(orderInfo.getSaleNo());
                    shipmentInfo.setShipOrderNo(shipmentOrderItem.getShipOrderNo());
                    shipmentInfo.setItems(new ArrayList<ItemInfo>());
                    //查询这个商品的是[自营/直发] 作为包裹属性

                    //构建item信息
                    ItemInfo orderItem = order_item_map.get(shipmentOrderItem.getItemId()); //在订单items中找商品其他信息
                    if (orderItem == null) {
                        logger.error("[订单详情|组建包裹] 异常，找不到商品信息 itemid="+shipmentOrderItem.getItemId());
                        continue;
                    }
                    shipmentInfo.setMode(orderItem.getItemForm());
                    //查询最后一条物流信息
                    List<SaleOrderTracking> saleOrderTrackings = null;
                    {
                        //查询物流信息
                        SaleOrderTrackingCriteria saleOrderTrackingCriteria = new SaleOrderTrackingCriteria();
                        //共通物流信息
                        SaleOrderTrackingCriteria.Criteria saleOrderTracking_Criteria1 = saleOrderTrackingCriteria.createCriteria();
                        saleOrderTracking_Criteria1.andSoNoEqualTo(sale_no).andShipOrderNoEqualTo("");
                        //某个包裹物流信息
                        SaleOrderTrackingCriteria.Criteria saleOrderTracking_Criteria2 = saleOrderTrackingCriteria.createCriteria();
                        saleOrderTracking_Criteria2.andSoNoEqualTo(sale_no).andShipOrderNoEqualTo(shipmentOrderItem.getShipOrderNo());
                        saleOrderTrackingCriteria.or(saleOrderTracking_Criteria2);

                        saleOrderTrackingCriteria.setOrderByClause("created_time desc");
                        saleOrderTrackings = saleOrderTrackingLogic.list(saleOrderTrackingCriteria, new RowBounds(1, 1));
                    }
                    SaleOrderTracking saleOrderTracking = saleOrderTrackings.size() > 0 ? saleOrderTrackings.get(0) : null;
                    if (saleOrderTracking != null) {
                        //最后一条物流信息
                        shipmentInfo.setLastTracking(TrackingEventMapping(saleOrderTracking));
                        //包裹状态
                        shipmentInfo.setStatus(TrackingEventStatusMapping(saleOrderTracking));
                    }
                    shipment_map.put(shipmentOrderItem.getShipOrderNo(), shipmentInfo);
                }

                //包裹中，组建商品
                ItemInfo itemInfo = new ItemInfo();
                itemInfo.setQuantity(shipmentOrderItem.getQuantity());
                //在订单items中找商品信息
                ItemInfo orderItem = order_item_map.get(shipmentOrderItem.getItemId());
                if (orderItem == null) {
                    logger.error("[订单详情|组建包裹] 异常，找不到商品信息 itemid="+shipmentOrderItem.getItemId());
                    continue;
                }
                itemInfo.setItemId(orderItem.getItemId());
                itemInfo.setImgUrl(orderItem.getImgUrl());
                itemInfo.setItemTitle(orderItem.getItemTitle());
                itemInfo.setItemForm(orderItem.getItemForm());
                itemInfo.setUnitPrice(orderItem.getUnitPrice());
                shipment_map.get(shipmentOrderItem.getShipOrderNo()).getItems().add(itemInfo);
            }

            //组装好的包裹信息放到orderinfo中
            orderInfo.setShipments(new ArrayList<ShipmentInfo>());
            for (ShipmentInfo shipmentInfo : shipment_map.values()) {
                orderInfo.getShipments().add(shipmentInfo);
            }

            //第二部分  not_ship_item_map 未发货商品组装到orderinfo ///////////////////////////////////////
            orderInfo.setItems(new ArrayList<ItemInfo>());
            if (not_ship_item_map.size() != 0) {
                //部分发货，订单肯定是确认状态之后，这里为了效率，就不去查数据库
                SaleOrderTracking saleOrderTracking = new SaleOrderTracking();
                saleOrderTracking.setEvent("订单确认");
                orderInfo.setLastTracking(TrackingEventMapping(saleOrderTracking));
                for (ItemInfo itemInfo : not_ship_item_map.values()) {
                    orderInfo.getItems().add(itemInfo);
                }
            }
        }
        return orderInfo;
    }

    /**
     * 根据优惠券ID获取优惠券信息
     *
     * @param public_wesen
     * @return
     */
    private VirtualProductInfo getPromoByPublicWesen(String public_wesen,long promo_id,int payStatus) throws ServiceException {
        VirtualProductInfo info = new VirtualProductInfo();
        PromoInfo promoInfo = new PromoInfo();
        try{
            if(payStatus != SaleOrderPayStatus.Paid.value()) {
                promoInfo = promoService.getPromoByPublicCode(public_wesen);
            }else {
                promoInfo = promoService.getPromoById(promo_id);
            }
            logger.info("[订单详情|虚拟商品信息]  返回内容="+Json.toJson(promoInfo));
        }catch (Exception ex){
            logger.error("【优惠服务|根据商品获取信息 in 订单详情页】 报错。错误信息："+ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDERDETAILPROMO_NOT_FOUND, "【优惠服务|根据优惠券ID获取信息 in 订单详情页】 报错 exMsg=" + ex.getMessage());
        }

        if (promoInfo != null) {
            info.setId(promoInfo.getId());
            info.setTitle(promoInfo.getTitle());
            info.setDesc(promoInfo.getDesc());
            info.setType(promoInfo.getType());
            info.setStart(promoInfo.getStart());
            info.setEnd(promoInfo.getEnd());
            info.setPcUrl(promoInfo.getPcUrl());
            info.setMobileUrl(promoInfo.getMobileUrl());
            info.setProductFrom(promoInfo.getProductFrom());
            info.setTerminal(promoInfo.getTerminal());
            info.setStatus(promoInfo.getStatus());
            info.setShop(promoInfo.getShop());
            info.setTip(promoInfo.getTip());
            info.setItems(promoInfo.getItems());
            info.setDifference(promoInfo.getDifference());
            info.setRuleid(promoInfo.getRules().getId());
            info.setLimit(promoInfo.getRules().getLimit());
            info.setPreferential(promoInfo.getRules().getPreferential());
            info.setRuledesc(promoInfo.getRules().getDesc());
            info.setCode(promoInfo.getCode());
            info.setBrand(promoInfo.getBrand()); //oto

        }
        return info;
    }

    /**
     * 虚拟商品订单 支付完成发券
     * @param so_no
     */
    @Transactional
    private void bindPromotionForVirtual(String so_no,String _terminal,String customer_id)throws ServiceException
    {
        List<SaleOrderItem> itemInfoList = getOrderItemList(so_no);
        List<SaleOrderItem> itemInfos = new ArrayList<SaleOrderItem>();
        if (itemInfoList != null && itemInfoList.size() > 0) {
            for (SaleOrderItem info : itemInfoList) {
                itemInfos = getPrivateWesen(info,_terminal,customer_id);
                if (itemInfos != null && itemInfos.size() > 0) {
                    saleOrderItemLogic.updateSelective(itemInfos.get(0));
                }
            }
        }
    }
    private  List<SaleOrderItem> getPrivateWesen(SaleOrderItem info,String _termail,String customer_id)throws ServiceException
    {
        List<SaleOrderItem> saleOrderItems= new ArrayList<SaleOrderItem>();
        List<PromoInfo> promoInfos=new ArrayList<PromoInfo>();
        try{
            
            RpcContext.getContext().setAttachment(ExtendParameter.terminal, _termail);
            RpcContext.getContext().setAttachment(CommonParameter.userId, customer_id);
            logger.info("getPrivateWesen:SetTermail= " + _termail + "\r\n " +
                    "GetTermal= "+ RpcContext.getContext().getAttachment(ExtendParameter.terminal)+"\r\n " +
                    "SetUserID= " + customer_id + " \r\n " +
                    "GetUserId= "+ RpcContext.getContext().getAttachment(CommonParameter.userId));
            promoInfos= promoService.exchangeMore(info.getPublicWesen(),info.getQuantity(),info.getSoNo());
        }catch (Exception ex)
        {
            logger.error("【优惠券服务|兑换券绑定 in 订单支付页】 报错 信息： PublicWesen="+info.getPublicWesen()+"  Quantity="+info.getQuantity()+" sono="+info.getSoNo());
            logger.error("【优惠券服务|兑换券绑定 in 订单支付页】 报错 信息：" + ex);
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDERPAYPROMO_NOT_FOUND, "【优惠券服务|兑换券绑定 in 订单支付页】 报错 exMsg=" + ex.getMessage());
        }
        if(promoInfos.size()>0 && promoInfos !=null){
            logger.error("【优惠券服务|根据公券获取私券信息】 优惠券服务返回信息 =" + Json.toJson(promoInfos)+"订单号："+info.getSoNo());
            for (PromoInfo promoInfo:promoInfos) {
                info.setPrivateWesen(promoInfo.getCode());
                info.setPromoId(promoInfo.getId());
                saleOrderItems.add(info);
            }
        }
        else
        {
            logger.error("【优惠券服务|根据公券获取私券信息】 优惠券服务返回信息为空! 订单号："+info.getSoNo());
        }
        return  saleOrderItems;
    }


    /**
     * 根据订单号获取订单返回信息
     *
     * @return
     */
    private SaleOrderInfo getOrderInfoBySo(String sale_no) {
        SaleOrderInfo orderInfo = null;

        SaleOrder saleOrder = getOrderBySo(sale_no);
        if (saleOrder == null) {
            return orderInfo;
        }
        orderInfo = orderInfoMapping(saleOrder);
        return orderInfo;
    }

    /**
     * 根据订单号获取订单信息
     *
     * @param sale_no
     * @return
     */
    private SaleOrder getOrderBySo(String sale_no) {
        SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
        saleOrderCriteria.createCriteria().andSaleNoEqualTo(sale_no);
        List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);
        SaleOrder saleOrder = saleOrderList.size() > 0 ? saleOrderList.get(0) : null;
        return saleOrder;
    }

    /**
     * 订单映射
     *
     * @param saleOrder
     * @return
     */
    private SaleOrderInfo orderInfoMapping(SaleOrder saleOrder) {
        SaleOrderInfo orderInfo = null;
        if (saleOrder == null) {
            return orderInfo;
        }
        orderInfo = new SaleOrderInfo();
        orderInfo.setOrderTime(saleOrder.getOrderTime().getTime());
        orderInfo.setSaleNo(saleOrder.getSaleNo());
        orderInfo.setShipDate(saleOrder.getShipDate().getTime());
        orderInfo.setOrderCategory(saleOrder.getOrderCategory());
        orderInfo.setGroupId(saleOrder.getGroupId());
        orderInfo.setPayStatus(saleOrder.getPayStatus());
        orderInfo.setPayType(saleOrder.getPayType());
        orderInfo.setSubAmount(saleOrder.getSubAmount().doubleValue());
        orderInfo.setPromotionDiscount(saleOrder.getPromotionDiscount().doubleValue());
        orderInfo.setProductCouponDiscount(saleOrder.getProductCouponDiscount().doubleValue());
        orderInfo.setShipFee(saleOrder.getShipFee().doubleValue());
        orderInfo.setShipFeeDiscount(saleOrder.getShipFeeDiscount().doubleValue());
        orderInfo.setShipFeeCouponDiscount(saleOrder.getShipFeeCouponDiscount().doubleValue());
        orderInfo.setTotalAmount(saleOrder.getTotalAmount().doubleValue());
        orderInfo.setPaidAmount(saleOrder.getPaidAmount().doubleValue());
        orderInfo.setCreatedBy(saleOrder.getCreatedBy());
        orderInfo.setStatus(saleOrder.getStatus());
        orderInfo.setStatusValue(OrderStatusMapping(saleOrder.getStatus(), saleOrder.getPayType(), saleOrder.getOrderCategory(), saleOrder.getPayStatus()));
        orderInfo.setRefundPartialPayActionCode(this.getCanPartialPayCancel(saleOrder.getSaleNo()));
        orderInfo.setPayChannel(saleOrder.getPayChannel()); //订单支付渠道

        return orderInfo;
    }

    /**
     * 订单状态，对UImapping
     */
    private String OrderStatusMapping(int status, String pay_type, String orderCategory, int payStatus) {
        /*待支付：  订单类型：显示支付 && 订单状态：1 创建
        待确认：   订单类型：货到付款，未同步  ||    支付完成未同步   ||  团购订单未同步
        处理中：  拆单后到订单完结前都是处理中
        已完成：  完成
        已取消：  取消 || 部分取消
        已退款：  团购订单，支付或部分支付的单子取消
        */
        switch (status) {
            case 1:// Created
                if (pay_type.equals("线上支付")) {
                    if(payStatus == SaleOrderPayStatus.PartialPay.value()) {
                        return "部分支付";
                    }else{
                        return "待支付";
                    }
                } else if (pay_type.equals("货到付款")) {
                    return "待确认";
                }else{
                    return "";
                }
            case 2://Confirmed
                return "待确认";
            case 3:
                return "处理中";//Splited
            case 4:
                return "处理中";//Synchronized
            case 5:
                return "处理中";//Shipping
            case 6:
                return "已完成";//Rejected
            case 7://Cancel
                if (orderCategory.equals("团购订单") && (payStatus != SaleOrderPayStatus.WaitPay.value())) {
                    return "已退款";
                }
                return "已取消";
            case 8://PartialCancel
                if (orderCategory.equals("团购订单") && (payStatus != SaleOrderPayStatus.WaitPay.value())) {
                    return "已退款";
                }
                return "已取消";
            case 9:
                return "处理中";//Suspension
            case 10:
                return "已完成";//Finished
            default:
                return "";
        }
    }

    /**
     * 订单状态， 反mapping
     */
    private List<HashMap<String, Object>> OrderStatusMappingAnalysis(String status) {
         /*待支付：  订单类型：显示支付 && 订单状态：1 创建
        待确认：   订单类型：货到付款，未同步  ||    支付完成未同步   ||  团购订单未同步
        处理中：  拆单后到订单完结前都是处理中
        已完成：  完成
        已取消：  取消 || 部分取消
        已退款：  团购订单，支付或部分支付的单子取消
        */

        if (status.equals("配送中")) {
            status = "处理中";
        }

        List<HashMap<String, Object>> rsMap = new ArrayList<HashMap<String, Object>>();

        List<Integer> list = new ArrayList<Integer>();
        HashMap<String, Object> map = new HashMap<>();

        switch (status) {
            case "待支付":
                list.add(1); //Created
                map.put("Status", list);
                map.put("PayType", "线上支付");
                rsMap.add(map);
                break;
            case "待确认":

                list.add(1); //Created
                map.put("Status", list);
                map.put("PayType", "货到付款");
                rsMap.add(map);

                List<Integer> list2 = new ArrayList<Integer>();
                HashMap<String, Object> map2 = new HashMap<>();
                list2.add(2); //Confirmed
                map2.put("Status", list2);
                rsMap.add(map2);
                break;
            case "处理中":
                list.add(3);    //Splited
                list.add(4);    //Synchronized
                list.add(5);    //Shipping
                list.add(9);    //Suspension
                map.put("Status", list);
                rsMap.add(map);
                break;
            case "已完成":
                list.add(6);    //Rejected
                list.add(10);    //Finished
                map.put("Status", list);
                rsMap.add(map);
                break;
            case "已取消":
                list.add(7);    //Cancel
                list.add(8);    //PartialCancel
                map.put("Status", list);
                rsMap.add(map);
                break;
            default:
                break;
        }
        return rsMap;
    }

    /**
     * 根据订单号获取配送返回信息
     *
     * @param sale_no
     * @return
     */
    private AddressInfo getAddressInfoBySo(String sale_no) {
        AddressInfo addressInfo = null;
        SaleOrderShip saleOrderShip = getShipBySo(sale_no);

        if (saleOrderShip == null) {
            return addressInfo;
        }

        addressInfo = new AddressInfo();
        addressInfo.setCity(saleOrderShip.getCity());
        addressInfo.setCityZone(saleOrderShip.getCityZone());
        addressInfo.setConsignee(saleOrderShip.getConsignee());
        addressInfo.setAddressDetail(saleOrderShip.getDetail());
        addressInfo.setMobile(saleOrderShip.getMobile());
        addressInfo.setProvince(saleOrderShip.getPrivince());
        return addressInfo;
    }

    /**
     * 根据订单号查询配送信息
     *
     * @param sale_no
     * @return
     */
    private SaleOrderShip getShipBySo(String sale_no) {
        SaleOrderShipCriteria saleOrderShipCriteria = new SaleOrderShipCriteria();
        saleOrderShipCriteria.createCriteria().andSoNoEqualTo(sale_no);
        List<SaleOrderShip> saleOrderShipList = saleOrderShipLogic.list(saleOrderShipCriteria);
        SaleOrderShip saleOrderShip = saleOrderShipList.size() > 0 ? saleOrderShipList.get(0) : null;
        return saleOrderShip;
    }

    /**
     * 根据订单号获取商品明细
     *
     * @param sale_no
     * @return
     */
    private List<ItemInfo> getOrderItemInfoList(String sale_no) {
        List<ItemInfo> itemInfoList = new ArrayList<ItemInfo>();

        List<SaleOrderItem> saleOrderItemList = getOrderItemList(sale_no);
        if (saleOrderItemList == null || saleOrderItemList.size() == 0) {
            return itemInfoList;
        }

        if (saleOrderItemList.size() > 0) {
            for (SaleOrderItem saleOrderItem : saleOrderItemList) {
                ItemInfo itemInfo = new ItemInfo();
                itemInfo.setImgUrl(saleOrderItem.getImgUrl());  //* 图片地址还要取
                itemInfo.setItemId(saleOrderItem.getItemId());
                itemInfo.setQuantity(saleOrderItem.getQuantity());
                itemInfo.setItemTitle(saleOrderItem.getItemTitle());
                itemInfo.setWeight(saleOrderItem.getWeight().doubleValue());
                itemInfo.setUnitPrice(saleOrderItem.getUnitPrice().doubleValue());
                itemInfo.setItemForm(saleOrderItem.getItemForm());
                itemInfo.setPromoId((saleOrderItem.getPromoId() == null) ? 0 : saleOrderItem.getPromoId());
                itemInfo.setPrivateWesen((saleOrderItem.getPrivateWesen() == null) ? "" : saleOrderItem.getPrivateWesen());
                itemInfo.setPublicWesen((saleOrderItem.getPublicWesen() == null) ? "" : saleOrderItem.getPublicWesen()); //oto
                itemInfo.setSubTotal((saleOrderItem.getUnitPrice().doubleValue() * saleOrderItem.getQuantity()));
                itemInfo.setSkuCode(saleOrderItem.getSkuCode());
                itemInfo.setSkuId(saleOrderItem.getSkuId());
                itemInfoList.add(itemInfo);
            }
        }
        return itemInfoList;
    }

    /**
     * 根据订单号获取商品信息
     *
     * @param sale_no
     * @return
     */
    private List<SaleOrderItem> getOrderItemList(String sale_no) {
        SaleOrderItemCriteria saleOrderItemCriteria = new SaleOrderItemCriteria();
        saleOrderItemCriteria.createCriteria().andSoNoEqualTo(sale_no);
        return saleOrderItemLogic.list(saleOrderItemCriteria);
    }

    /**
     * 获取支付操作code
     *
     * @param status    订单状态
     * @param payStatus 订单支付状态
     * @return
     */
    private String getPayActionCode(int status, String pay_type, String orderCategory, int payStatus) {
        //支付code说明：  可支付：CanPay  部分支付： PartialPay 不可支付：CannotPay
        String rtnCode = "CannotPay";

        String statusValue = OrderStatusMapping(status, pay_type, orderCategory, payStatus);
        if (statusValue.equals("待支付")) {
            if (payStatus == 1) {
                rtnCode = "CanPay";
            } else if (payStatus == 2) {
                rtnCode = "PartialPay";
            }
        }else if(statusValue.equals("部分支付")){
            rtnCode = "PartialPay";
        }
        return rtnCode;
    }

    /**
     * 获取取消操作code <br /> 有效返回值如下：
     * CanCancel : 可以取消
     * CannotCancel : 不可以取消
     * CanPayCancel : 可以取消并退还余额
     *
     * @param status 订单状态
     * @param pay_type 订单支付状态
     * @param actionCode 留给团购使用，团购失败时取消
     * @return
     */
    private String getCancelActionCode(int status, String pay_type, String actionCode, String orderCategory, int payStatus) {
        //取消code说明：  取消操作code  可取消：CanCancel   不可取消： CannotCancel
        String rtnCode = "CannotCancel";

        String statusValue = OrderStatusMapping(status, pay_type, orderCategory, payStatus);
        if (statusValue.equals("待支付")) {
            //部分支付（必须保证部分支付为余额支付）也可取消
            if (payStatus == SaleOrderPayStatus.WaitPay.value()) {
                rtnCode = "CanCancel";
            }
        }else if(statusValue.equals("部分支付")){
            rtnCode = "CanPayCancel";
        }

        //额外的取消逻辑
        if (actionCode != null && !actionCode.isEmpty()) {
            if (actionCode.equals("GroupFailed")) {
                //如果是成团失败,同步之前都可以取消
                if (statusValue.equals("待确认")) {
                    rtnCode = "CanCancel";
                }
            }
        }
        return rtnCode;
    }

    /**
     * 订单配送信息
     *
     * @param sale_no
     * @param ship_order_no
     * @return
     * @throws ServiceException
     */
    @Override
    public List<TrackingInfo> tracking(@ApiParameter(required = true, name = "sale_no", desc = "订单号") String sale_no,
                                       @ApiParameter(required = false, name = "ship_order_no", desc = "包裹号") String ship_order_no) throws ServiceException {

        List<TrackingInfo> list = new ArrayList<TrackingInfo>();
        //查询物流信息
        SaleOrderTrackingCriteria saleOrderTrackingCriteria = new SaleOrderTrackingCriteria();

        //共通物流信息
        SaleOrderTrackingCriteria.Criteria criteria1 = saleOrderTrackingCriteria.createCriteria();
        criteria1.andSoNoEqualTo(sale_no).andShipOrderNoEqualTo("").andEventNotEqualTo("已发货").andEventNotEqualTo("已交接");
        //某个包裹物流信息
        if (ship_order_no != null && !ship_order_no.isEmpty()) {
            SaleOrderTrackingCriteria.Criteria criteria2 = saleOrderTrackingCriteria.createCriteria();
            criteria2.andSoNoEqualTo(sale_no).andShipOrderNoEqualTo(ship_order_no);
            saleOrderTrackingCriteria.or(criteria2);
        }

        saleOrderTrackingCriteria.setOrderByClause("created_time desc");

        List<SaleOrderTracking> trackingList = saleOrderTrackingLogic.list(saleOrderTrackingCriteria);

        if (trackingList == null || trackingList.size() == 0) {
            return list;
        }

        //增加一个发货单号信息
        TrackingInfo trackingInfo_shipOrderNO = new TrackingInfo();
        trackingInfo_shipOrderNO.setDetails("发货单号：" + ship_order_no);
        trackingInfo_shipOrderNO.setTime(new Date().getTime());
        list.add(trackingInfo_shipOrderNO);


        for (SaleOrderTracking saleOrderTracking : trackingList) {
            TrackingInfo trackingInfo = new TrackingInfo();
            trackingInfo.setDetails(TrackingEventMapping(saleOrderTracking));
            trackingInfo.setTime(saleOrderTracking.getCreatedTime().getTime());
            list.add(trackingInfo);
        }
        return list;
    }

    /**
     * 根据event获取物流显示值
     */
    private String TrackingEventMapping(SaleOrderTracking saleOrderTracking) {
        String eventName = saleOrderTracking.getEvent();
        if ("订单创建".equals(eventName)) {
            return "您提交了订单,等待系统确认。";
        } else if ("订单确认".equals(eventName)) {
            return "您支付了订单,系统已确认,准备出库。";
        } else if ("订单打印".equals(eventName)) {
            return "您的订单已打印完毕。";
        } else if ("拣货完成".equals(eventName)) {
            return "您的包裹已拣货完成,等待发货中。";
        } else if ("打包完成".equals(eventName)) {
            return "您的包裹已打包完成。";
        } else if ("已交接".equals(eventName)) {
            return "您的包裹将交接给分站点即将出库。";
        } else if ("已发货".equals(eventName)) {
            return "您的订单已发货并交接给分站点,即将配送。";
        } else if ("开始配送".equals(eventName)) {
            return "开始配送-配送员【" + saleOrderTracking.getOperatorName() + "】，联系电话【" + saleOrderTracking.getOperatorMobileNo() + "】正在配送中。";
        } else if ("客户签收".equals(eventName)) {
            return "您的订单已签收。";
        } else if ("客户拒收".equals(eventName)) {
            return "您的包裹已拒收。";
        } else if ("交易成功".equals(eventName)) {
            return "您的订单交易成功。";
        } else {
            return eventName;
        }
    }

    /**
     * 根据物流信息，整理包裹状态
     *
     * @param saleOrderTracking
     * @return
     */
    private String TrackingEventStatusMapping(SaleOrderTracking saleOrderTracking) {
        String eventName = saleOrderTracking.getEvent();
        if ("订单创建".equals(eventName)) {
            return "等待发货";
        } else if ("订单确认".equals(eventName)) {
            return "等待发货";
        } else if ("订单打印".equals(eventName)) {
            return "等待发货";
        } else if ("拣货完成".equals(eventName)) {
            return "等待发货";
        } else if ("打包完成".equals(eventName)) {
            return "等待发货";
        } else if ("已交接".equals(eventName)) {
            return "配送中";
        } else if ("已发货".equals(eventName)) {
            return "配送中";
        } else if ("开始配送".equals(eventName)) {
            return "配送中";
        } else if ("客户签收".equals(eventName)) {
            return "已签收";
        } else if ("客户拒收".equals(eventName)) {
            return "已拒收";
        } else if ("交易成功".equals(eventName)) {
            return "已签收";
        } else {
            return "";
        }
    }

    /**
     * 订单个数
     *
     * @param status
     * @param start_date
     * @param end_date
     * @return
     * @throws ServiceException
     */
    @Override
    public int count(@ApiParameter(required = false, name = "status", desc = "订单状态") String status,
                     @ApiParameter(required = false, name = "start_date", desc = "订单开始时间") long start_date,
                     @ApiParameter(required = false, name = "end_date", desc = "订单开始时间") long end_date) throws ServiceException {

        String customerId = RpcContext.getContext().getAttachment(CommonParameter.userId);
        long customer_id = Long.parseLong(customerId);
        //查询订单信息
        SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
        //根据条件拼接sql
        String ExtendSql = ExtendOrderSql(customerId, status, start_date, end_date, "", 0, 0);

        return saleOrderLogic.countExtendSql(new SQLAdapter(ExtendSql));
    }

    @Override
    /**
     * 取消订单
     */
    public OrderStatusInfo cancel(@ApiParameter(required = true, name = "sale_no", desc = "订单号") String sale_no) throws ServiceException {
        ;
        return cancel(sale_no, "system", "");
    }


    //region 首单

    /**
     * 查询首单
     * @param customer_id
     * @return
     */
    @Override
    public String fristOrder(long customer_id)
    {
        String fristSaleNo = "";
        CustomerFirstSale customerFirstSale = getFristOrder(customer_id);
        if (customerFirstSale!=null)
        {
            fristSaleNo = customerFirstSale.getSoNo();
        }
        return  fristSaleNo;
    }

    /**
     * 查询首单
     * @param customer_id
     * @return
     */
    private CustomerFirstSale getFristOrder(long customer_id)
    {
        CustomerFirstSale customerFirstSale = null;
        try{
            CustomerFirstSaleCriteria customerFirstSaleCriteria = new CustomerFirstSaleCriteria();
            customerFirstSaleCriteria.createCriteria().andCustomerIdEqualTo(customer_id).andIsDeleteEqualTo(0);
            List<CustomerFirstSale> customerFirstSales = customerFirstSaleLogic.list(customerFirstSaleCriteria);

            if (customerFirstSales !=null&&customerFirstSales.size()>0)
            {
                customerFirstSale = customerFirstSales.get(0);
            }
            return customerFirstSale;
        }catch (Exception ex)
        {
            logger.error("[查询首单|查询首单方法] 报错 信息："+ex.getMessage());
            logger.error(ex);
            return  customerFirstSale;
        }
    }

    /**
     * 保存首单
     * @param sale_no
     * @param customer_id
     */
    private void saveFristOrder(String sale_no,long customer_id)
    {
        CustomerFirstSale customerFirstSale = getFristOrder(customer_id);
        if (customerFirstSale!=null)
        {
            //已经存在首单就返回
            return;
        }
        else {
            try {
                //保存首单
                CustomerFirstSale customerFirstSale_i = new CustomerFirstSale();
                customerFirstSale_i.setCustomerId(customer_id);
                customerFirstSale_i.setSoNo(sale_no);
                customerFirstSale_i.setIsDelete(0);
                customerFirstSale_i.setVersion(1);
                customerFirstSale_i.setModifiedBy("system");
                customerFirstSale_i.setModifiedTime(new Date());
                customerFirstSale_i.setCreatedBy("system");
                customerFirstSale_i.setCreatedTime(new Date(0));
                customerFirstSaleLogic.insert(customerFirstSale_i);
            }catch (Exception ex)
            {
                logger.error("[保存首单] 报错 信息："+ex.getMessage());
                logger.error(ex);
            }
        }
    }

    /**
     * 删除首单
     * @param customer_id
     */
    private void delFristOrder(String sale_no,long customer_id)
    {
        try{
            CustomerFirstSaleCriteria customerFirstSaleCriteria = new CustomerFirstSaleCriteria();
            customerFirstSaleCriteria.createCriteria().andCustomerIdEqualTo(customer_id).andSoNoEqualTo(sale_no).andIsDeleteEqualTo(0);
            List<CustomerFirstSale> customerFirstSales = customerFirstSaleLogic.list(customerFirstSaleCriteria);

            if (customerFirstSales !=null&&customerFirstSales.size()>0)
            {
                CustomerFirstSale customerFirstSale = customerFirstSales.get(0);
                customerFirstSale.setIsDelete(1);
                customerFirstSale.setModifiedBy("system");
                customerFirstSale.setModifyTime(new Date());
                customerFirstSaleLogic.update(customerFirstSale);
            }
        }catch (Exception ex)
        {
            logger.error("[删除首单|删除首单方法] 报错 信息："+ex.getMessage());
            logger.error(ex);
        }
    }

    //endregion 首单

    /**
     * 构建查询order表sql
     *
     * @param customerId 【必要参数】
     * @param status
     * @param start_date
     * @param end_date
     * @param rows       开始行
     * @param page       分页大小
     * @return
     */
    private String ExtendOrderSql(String customerId, String status, long start_date, long end_date, String orderBy, int rows, int page) {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        StringBuilder sbd = new StringBuilder();

        //用户ID
        sbd.append("customer_id='" + customerId + "' ");

        //主订单
        sbd.append("and order_type='main' ");

        //订单时间范围
        if (start_date != 0) {
            sbd.append("and created_time>='" + dateFormat.format(new Date(start_date)) + "' ");
        } else if (end_date != 0) {
            sbd.append("and created_time<='" + dateFormat.format(new Date(end_date)) + "' ");
        }

        if (status != null && !status.isEmpty()) {
            List<HashMap<String, Object>> rsMapList = OrderStatusMappingAnalysis(status);
            if (rsMapList != null && rsMapList.size() > 0) {
                sbd.append("and ( ");
                int rscount = 0;
                for (HashMap<String, Object> rsMap : rsMapList) {
                    rscount++;
                    if (rscount != 1) {
                        sbd.append("or ");
                    }
                    sbd.append("( ");
                    ArrayList<List<Integer>> statusList = (ArrayList<List<Integer>>) rsMap.get("Status");
                    sbd.append("status in (");
                    for (int i = 0; i < statusList.size(); i++) {
                        if (i != 0) {
                            sbd.append(",");
                        }
                        sbd.append(statusList.get(i));
                    }
                    sbd.append(") ");

                    if (rsMap.containsKey("PayType")) {
                        sbd.append("and pay_type='" + rsMap.get("PayType").toString() + "'");
                    }
                    sbd.append(") ");
                }
                sbd.append(" ) ");
            }
        }

        if (orderBy != null && !orderBy.isEmpty()) {
            sbd.append("order by " + orderBy + " ");
        }

        if (rows != 0 || page != 0) {
            sbd.append("limit " + rows + "," + page + " ");
        }

        return sbd.toString();
    }


    //endregion--------------------------------------------上面是页面调用的接口-------------------------------------------------------------

    //region--------------------------------------------下面是内部调用的接口-------------------------------------------------------------

    @Override
    public OrderStatusInfo internalCancel(@ApiParameter(required = true, name = "sale_no", desc = "订单号") String sale_no,
                                          @ApiParameter(required = false, name = "operator_id", desc = "操作人") String operator_id,
                                          @ApiParameter(required = false, name = "action_code", desc = "操作code 【团购：GroupFailed】") String actionCode) throws ServiceException {
        logger.info("[取消订单|取消订单 in internalCancel ] 请求参数： sale_no=" + sale_no + "   operator_id" + operator_id + " action_code" + actionCode);

        //条件判断
        return cancel(sale_no, operator_id, actionCode);
    }

    /**
     * 取消订单
     *
     * @param sale_no
     * @param operator_id
     * @return
     */
    private OrderStatusInfo cancel(String sale_no, String operator_id, String actionCode) throws ServiceException {
        OrderStatusInfo orderStatusInfo = new OrderStatusInfo();
        //条件判断
        if (sale_no == null || sale_no.isEmpty()) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }
        //查询订单
        SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
        saleOrderCriteria.createCriteria().andSaleNoEqualTo(sale_no);
        List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);
        SaleOrder saleOrder = saleOrderList.size() > 0 ? saleOrderList.get(0) : null;

        if (saleOrder == null) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }

        //如果是取消订单直接返回成功
        if (saleOrder.getStatus() == SaleOrderStatus.Cancel.value()) {
            orderStatusInfo.setSaleNo(saleOrder.getSaleNo());
            orderStatusInfo.setStatus(saleOrder.getStatus());
            return orderStatusInfo;
        }

        if("虚拟商品订单".equalsIgnoreCase(saleOrder.getOrderCategory())){
            //020退款的情况,不要做下面的检查了,直接退款.
            boolean refoundResult = OrderRefoundAmount(sale_no);
            if (!refoundResult) {
                logger.error("o2o退款异常["+sale_no+"]");
                //throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_REFUNDAMOUNT_ERROR);
            }
        }else{
            String CancelAction = getCancelActionCode(saleOrder.getStatus(), saleOrder.getPayType(), actionCode, saleOrder.getOrderCategory(), saleOrder.getPayStatus());
            if(CancelAction.equals("CanPayCancel")){
                //region 余额部分支付退款操作
                logger.info("部分支付订单取消并退款：" + sale_no);
                RefundResultInfo result  = this.partialPayCancel(sale_no);
                if(!result.getStatus()){
                    logger.error("部分支付订单取消并退款失败(" + sale_no + ")" + result.getMsg());
                    throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_REFUNDAMOUNT_ERROR);
                }
                //endregion
            }else{
                //region 正常取消订单流程
                if (!CancelAction.equals("CanCancel")) {
                    logger.error("订单不能取消：Status=" + saleOrder.getStatus() + " PayType=" + saleOrder.getPayType());

                    //这里对于团购优化下
            /*有时修数据，团购未成团的，当作正常单子处理了，也是合理的，但是自动单子一直认为状态有问题，不可以取消，
            这里接口返回取消成功，防止团购一直取消订单，一直不成功，死循环。 【团购可以取消订单做异常处理，n次取消不成功后就不取消了】*/
                    if (actionCode.equals("GroupFailed"))
                    {
                        orderStatusInfo.setStatus(SaleOrderStatus.Cancel.value());
                        return orderStatusInfo;
                    }
                    throw new ServiceException(OrderErrorCodes.getErrorCodes_ORDER_STATUS_ERROR);
                }

                if (actionCode.equals("GroupFailed")) {
                    boolean refoundResult = OrderRefoundAmount(sale_no);
                    if (!refoundResult) {
                        logger.error("退款异常");
                        throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_REFUNDAMOUNT_ERROR);
                    }
                }
                //endregion
            }
        }

        //修改状态
        SaleOrder saleOrder_update = new SaleOrder();
        saleOrder_update.setId(saleOrder.getId());
        saleOrder_update.setStatus(SaleOrderStatus.Cancel.value());
        saleOrder_update.setModifiedTime(new Date());
        saleOrder_update.setVersion(saleOrder.getVersion());
        if (operator_id != null && !operator_id.isEmpty()) {
            saleOrder_update.setModifiedBy(operator_id);
        } else {
            saleOrder_update.setModifiedBy("system");
        }
        saleOrderLogic.updateSelective(saleOrder_update);

        //库存退还
        rollbackStock(sale_no);

        //如果是团购订单推送消息
        sendGroupMsg(saleOrder, 0);

        //退还优惠券
        promotionRecoveryBySaleOrder(saleOrder);

        //退还下单数
        addDaliyLimitCache(saleOrder.getShipDate());

        //取消首单
        delFristOrder(saleOrder.getSaleNo(),saleOrder.getCustomerId());

        //[优惠服务]银行支付优惠使用状态更新
        CancelPromotionUpdateStatus(saleOrder.getSaleNo(),saleOrder.getCustomerId());

        orderStatusInfo.setSaleNo(saleOrder.getSaleNo());
        orderStatusInfo.setStatus(saleOrder_update.getStatus());
        return orderStatusInfo;
    }


    /**
     * 取消订单银行满减-银行支付优惠使用状态更新
     * @param sale_no
     * @throws ServiceException
     */
    private  void CancelPromotionUpdateStatus(String sale_no,long customer_id)throws  ServiceException{

        String _customer_id = customer_id==0?null:Long.toString(customer_id);
        RpcContext.getContext().setAttachment(CommonParameter.userId, _customer_id);

        SaleOrderPayCriteria saleOrderPayCriteria = new SaleOrderPayCriteria();
        saleOrderPayCriteria.createCriteria().andSoNoEqualTo(sale_no).andBankPromotionIdGreaterThan(0L);
        List<SaleOrderPay> promotions = saleOrderPayLogic.list(saleOrderPayCriteria);
        if (promotions != null && promotions.size() > 0) {
            for(SaleOrderPay orderpays:promotions){
                try{
                    Results  results= promoService.promoPayLogUpdateStatus(orderpays.getBankPromotionId(),orderpays.getSoNo(),-1);

                    if(results==null || !results.success){
                        throw new Exception(results == null ? "" : results.getMessage());
                    }else {
                        String content = "CancelResult:BankPromotionId:\r\n"+ orderpays.getBankPromotionId()+"\r\n"
                                +"sale_no:\r\n"+ orderpays.getSoNo()+"\r\n" + "userId:\r\n" + _customer_id+"\r\n";
                        logger.info("[优惠服务|银行支付优惠使用状态更新] 传递参数:"+ content);
                        logger.info("[优惠服务|银行支付优惠使用状态更新] 返回数据:"+ " results: messages=\r\n"+ results.getMessage()+";success=\r\n"+results.success);
                    }
                }catch (Exception ex)
                {
                    logger.error(String.format("[优惠服务|银行支付优惠使用状态更新报错] msg+", ex.getMessage()));
                    logger.error(ex);
                    throw new ServiceException(OrderErrorCodes.errorCodes_PAY_PAYERROR, "[优惠服务|银行支付优惠使用状态更新]" + ex.getMessage());
                }
            }

        }
    }
    /**
     * 订单支付回调-银行满减-银行支付优惠使用状态更新
     * @param sale_no
     * @throws ServiceException
     */
    private  void PayResultPromotionUpdateStatus(String sale_no,long pay_id,long customer_id)throws  ServiceException{

        String _customer_id = Long.toString(customer_id);

        RpcContext.getContext().setAttachment(CommonParameter.userId, _customer_id);


        SaleOrderPayCriteria saleOrderPayCriteria = new SaleOrderPayCriteria();
        saleOrderPayCriteria.createCriteria()
                .andSoNoEqualTo(sale_no)
                .andBankPromotionIdGreaterThan(0L)
                .andPayIdNotEqualTo(pay_id)
                .andStatusEqualTo(0);
        List<SaleOrderPay> promotions = saleOrderPayLogic.list(saleOrderPayCriteria);
        if (promotions != null && promotions.size() > 0) {
            for(SaleOrderPay orderpays : promotions){
                try{
                    Results results = promoService.promoPayLogUpdateStatus(orderpays.getBankPromotionId(),orderpays.getSoNo(),-1);

                    if(results == null || !results.success){
                        throw new Exception(results == null ? "返回结果为：NULL": results.getMessage());
                    }else{
                        String content = "PayResults:BankPromotionId:\r\n"+ orderpays.getBankPromotionId()+"\r\n"
                                +"sale_no:\r\n"+ orderpays.getSoNo()+"\r\n" + "userId:\r\n"
                                + _customer_id+"\r\n";
                        logger.info("[优惠服务|银行支付优惠使用状态更新] 传递参数:"+ content);
                        logger.info("[优惠服务|银行支付优惠使用状态更新] 返回数据:"+ " payresults: messages=\r\n"+ results.getMessage() + ";success=\r\n" + results.success);
                    }
                }catch (Exception ex)
                {
                    logger.error(String.format("[优惠服务|银行支付优惠使用状态更新报错] msg+", ex.getMessage()));
                    logger.error(ex);
                    throw new ServiceException(OrderErrorCodes.errorCodes_PAY_PAYERROR, "[优惠服务|银行支付优惠使用状态更新]" + ex.getMessage());
                }
            }

        }
    }
    /**
     * 退款
     *
     * @param sale_no
     * @throws ServiceException
     */
    private boolean OrderRefoundAmount(String sale_no) throws ServiceException {
        boolean rtn = false;
        try {
            //【查询用户支付记录】
            SaleOrderPayCriteria saleOrderPayCriteria = new SaleOrderPayCriteria();
            saleOrderPayCriteria.createCriteria()
                    .andSoNoEqualTo(sale_no)
                    .andStatusEqualTo(PayStatus.Success.value());
            List<SaleOrderPay> saleOrderPays = saleOrderPayLogic.list(saleOrderPayCriteria);
            if (saleOrderPays != null && saleOrderPays.size() > 0) {
                //有支付记录去做退款   退款分2种：  支付退款；余额退款
                long balanceCount = saleOrderPays.stream().filter(m -> m.getPayChannel().equals("Balance")).count();
                if (balanceCount > 0) {
                    //如果有余额支付 预警
                    logger.error("退款订单中有余额支付");
                    return rtn;
                } else {
                    //没有余额支付 做退款
                    List<SaleOrderPay> saleOrderPays_refound = saleOrderPays.stream().filter(m -> !m.getPayChannel().equals("Balance")).collect(Collectors.toList());
                    if (saleOrderPays_refound != null && saleOrderPays_refound.size() > 0) {
                        if (saleOrderPays_refound.size() > 1) {
                            logger.error("多个银行支付，无法退款");
                            //邮件
                            return rtn;
                        } else {
                            //支付记录
                            SaleOrderPay saleOrderPay = saleOrderPays_refound.get(0);

                            //查询退款记录
                            SaleOrderRefundCriteria saleOrderRefundCriteria = new SaleOrderRefundCriteria();
                            saleOrderRefundCriteria.createCriteria().andSoNoEqualTo(sale_no).andStatusNotEqualTo(RefundStatus.Succeed.value());
                            List<SaleOrderRefund> saleOrderRefunds = saleOrderRefundLogic.list(saleOrderPayCriteria);

                            //不成功的订单有多条
                            if (saleOrderRefunds != null && saleOrderRefunds.size() > 1) {
                                logger.error("之前退款记录有多条");
                                return rtn;
                            }

                            //有一条继续退
                            if (saleOrderRefunds != null && saleOrderRefunds.size() == 1) {
                                SaleOrderRefund saleOrderRefund = saleOrderRefunds.get(0);
                                rtn = RefoundAmountToPT(saleOrderRefund, saleOrderPay);

                                if (rtn) {
                                    saleOrderRefund.setStatus(RefundStatus.Succeed.value());
                                    saleOrderRefundLogic.update(saleOrderRefund);
                                }
                            }

                            //一条都没有
                            if (saleOrderRefunds == null || saleOrderRefunds.size() == 0) {
                                SaleOrderRefund saleOrderRefund = new SaleOrderRefund();
                                saleOrderRefund.setSoNo(sale_no);
                                saleOrderRefund.setPayChannel(saleOrderPay.getPayChannel());
                                saleOrderRefund.setPayId(saleOrderPay.getId());
                                saleOrderRefund.setAmount(saleOrderPay.getAmount());
                                saleOrderRefund.setCreatedBy("system");
                                saleOrderRefund.setCreatedTime(new Date());
                                saleOrderRefund.setModifiedBy("system");
                                saleOrderRefund.setModifiedTime(new Date());
                                saleOrderRefund.setStatus(RefundStatus.Created.value());
                                saleOrderRefundLogic.insertSelective(saleOrderRefund);

                                rtn = RefoundAmountToPT(saleOrderRefund, saleOrderPay);
                                if (rtn) {
                                    saleOrderRefund.setStatus(RefundStatus.Succeed.value());
                                    saleOrderRefundLogic.update(saleOrderRefund);
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) {
            logger.error("退款失败");
            logger.error(ex);
            return rtn;
        }
        return rtn;
    }

    /**
     * 请求支付平台退款
     *
     * @param saleOrderRefund
     * @param saleOrderPay
     * @return
     */
    private boolean RefoundAmountToPT(SaleOrderRefund saleOrderRefund, SaleOrderPay saleOrderPay) {
        boolean rtn = false;
        logger.info("退款信息 =" + Json.toJson(saleOrderRefund));
        logger.info("退款信息 =" + Json.toJson(saleOrderPay));
        RefundRequest refundRequest = new RefundRequest();
        refundRequest.setAmount(new DecimalFormat("####0.00").format(saleOrderRefund.getAmount()));
        refundRequest.setMerchantId("1001");
        refundRequest.setOrderId(saleOrderRefund.getSoNo());
        refundRequest.setPaymentSerialNumber(saleOrderPay.getId().toString());
        refundRequest.setSerialNumber(saleOrderRefund.getId().toString());
        refundRequest.setBankPaymentSerialNumber(saleOrderPay.getBankSerialNo());
        //签名
        StringBuffer signature = new StringBuffer();
        signature
                .append("AMOUNT").append("=").append(new DecimalFormat("####0.00").format(saleOrderRefund.getAmount())).append("&")
                .append("BANKPAYMENTSERIALNUMBER").append("=").append(saleOrderPay.getBankSerialNo()).append("&")
                .append("MERCHANTID").append("=").append(refundRequest.getMerchantId()).append("&")
                .append("ORDERID").append("=").append(refundRequest.getOrderId()).append("&")
                .append("PAYMENTSERIALNUMBER").append("=").append(refundRequest.getPaymentSerialNumber()).append("&")
                .append("SERIALNUMBER").append("=").append(refundRequest.getSerialNumber()).append("&")
                .append("KEY").append("=").append(getAppKey("1001"));

        refundRequest.setSignature(DigestUtils.md5Hex(signature.toString()));

        List<NameValuePair> list = new ArrayList<NameValuePair>();
        list.add(new BasicNameValuePair("para", Json.toJson(refundRequest)));
        try {
                                /*Success = 1,
                                Failure = 2,
                                Repeat = 3,
                                StatusError = 4,*/
            String refundResponseStr = doPost(payRefundUrl, "utf-8", list);
            logger.info("[退款| 请求支付平台]返回信息：" + refundResponseStr);
            RefundResponse refundResponse = Json.fromJson(refundResponseStr, RefundResponse.class);
            if (refundResponse.getCode().equals("1")) {
                rtn = true;
            } else if (refundResponse.getCode().equals("2")) {
                rtn = false;
            } else if (refundResponse.getCode().equals("3")) {
                rtn = true;
            } else if (refundResponse.getCode().equals("4")) {
                rtn = false;
            }
        } catch (Exception ex) {
            logger.error("请求支付平台退款失败");
            logger.error(ex);
        }

        return rtn;
    }

    @Override
    public List<OrderSkuStock> stockHolding() throws ServiceException {
        return new ArrayList<>();//todo
    }

    /**
     * 成团通知
     *
     * @param group_id
     * @return
     * @throws ServiceException
     */
    @Override
    public GroupResultInfo groupResult(@ApiParameter(required = true, name = "group_id", desc = "团购ID") long group_id) throws ServiceException {
        GroupResultInfo groupResultInfo = new GroupResultInfo();
        groupResultInfo.setCode("Failed");

        logger.debug("debug[成团通知|成团通知方法 in 团通知方法INFO] group_id=" + group_id);

        try {
            //查询要处理的单子
            SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
            saleOrderCriteria.createCriteria().andGroupIdEqualTo(group_id).andSplitEnableEqualTo(0); //订单是否可拆  0：不可以  1：可以
            List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);

            if (saleOrderList == null || saleOrderList.size() == 0) {
                logger.error("【团购通知】 该团没有可处理订单：" + group_id);
                groupResultInfo.setCode("Succeed");
                return groupResultInfo;
            }

            List<String> succeedList = new ArrayList<String>();
            List<String> failedList = new ArrayList<String>();
            groupResultInfo.setCode("Succeed");
            for (SaleOrder saleOrder : saleOrderList) {
                try {

                    //配送时间校验
                    //团购订单的配送时间
                    //团购订单，20：30点前成团，配送日期T+1，20：30点后配送日期T+2
                    Calendar instance = Calendar.getInstance();
                    if (instance.get(Calendar.HOUR_OF_DAY) > 20
                            || (instance.get(Calendar.HOUR_OF_DAY) == 20 && instance.get(Calendar.MINUTE) >= 30)) {
                        instance.add(Calendar.DATE, 2);
                    } else {
                        instance.add(Calendar.DATE, 1);
                    }
                    saleOrder.setShipDate(instance.getTime());

                    saleOrder.setSplitEnable(1); //订单是否可拆  0：不可以  1：可以
                    saleOrderLogic.updateSelective(saleOrder);
                    succeedList.add(saleOrder.getSaleNo());
                } catch (Exception ex) {
                    groupResultInfo.setCode("PartialSucceed");
                    failedList.add(saleOrder.getSaleNo());
                    logger.error("【团购通知】 单个订单处理错误 订单号：" + saleOrder.getSaleNo());
                    logger.error(ex);
                }
            }
            groupResultInfo.setSucceedOrderIDs(succeedList);
            groupResultInfo.setFailedOrderIDs(failedList);
        } catch (Exception ex) {
            groupResultInfo.setCode("Failed");
            logger.error("团购通知处理失败");
            logger.error(ex);
        }
        return groupResultInfo;
    }
    //endregion--------------------------------------------上面是内部调用的接口----------------------------------------------------------

    //region--------------------------------------------下面是服务的接口-------------------------------------------------------------

    @Override
    public String sync() throws ServiceException {
        return schedule.sync();
    }

    @Override
    public String split() throws ServiceException {
        return schedule.split();
    }

    @Override
    public String autoCancel() throws ServiceException {
        return schedule.autoCancel();
    }

    @Override
    public String push() throws ServiceException {
        return schedule.push();
    }

    //endregion--------------------------------------------下面是服务的接口-------------------------------------------------------------

    //region--------------------------------------------下面是暂时不用的接口--------------------------------------------------------------------
    @Override
    public List<SaleOrderInfo> subList(@ApiParameter(required = true, name = "customer_id", desc = "用户ID") long customer_id,
                                       @ApiParameter(required = true, name = "package_sale_no", desc = "主订单单号") String package_sale_no,
                                       @ApiParameter(required = true, name = "status", desc = "订单状态") int status,
                                       @ApiParameter(required = true, name = "start_date", desc = "订单开始时间") long start_date,
                                       @ApiParameter(required = true, name = "end_date", desc = "订单开始时间") long end_date,
                                       @ApiParameter(required = true, name = "page", desc = "第n页") int page,
                                       @ApiParameter(required = true, name = "page", desc = "分页条数") int pagesiz) throws ServiceException {

        //判断数据参数是否正确
        if (package_sale_no == null || package_sale_no.isEmpty()) {
            throw new ServiceException(OrderErrorCodes.getErrorCodes_ORDER_INPUT_ERROR);
        }

        List<SaleOrderInfo> saleOrderInfoList = new ArrayList<SaleOrderInfo>();

        //查询订单信息
        SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
        saleOrderCriteria.createCriteria();
        SaleOrderCriteria.Criteria criteria = saleOrderCriteria.createCriteria();

        if (package_sale_no != null && !package_sale_no.isEmpty()) {
//            saleOrderCriteria.andPackageSaleNoEqualTo(package_sale_no);
        }

                /*.andPackageSaleNoEqualTo(package_sale_no)
                .andCustomerIdEqualTo(customer_id)
                .andStatusEqualTo(status);*/

        List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);

        //没有则返回
        if (saleOrderList.size() == 0) {
            return saleOrderInfoList;
        }

        //循环组织订单信息
        for (SaleOrder saleOrder : saleOrderList) {
            if (saleOrder == null) {
                continue;
            }

            SaleOrderInfo saleOrderInfo = new SaleOrderInfo();
            saleOrderInfo.setOrderTime(saleOrder.getOrderTime().getTime());
            saleOrderInfo.setSaleNo(saleOrder.getSaleNo());
            saleOrderInfo.setShipDate(saleOrder.getShipDate().getTime());
            saleOrderInfo.setStatusValue("");

            //查询商品信息
            SaleOrderItemCriteria saleOrderItemCriteria = new SaleOrderItemCriteria();
            saleOrderItemCriteria.createCriteria().andSoNoEqualTo(saleOrderInfo.getSaleNo());
            List<SaleOrderItem> saleOrderItemList = saleOrderItemLogic.list(saleOrderItemCriteria);

            List<ItemInfo> itemInfoList = new ArrayList<ItemInfo>();
            if (saleOrderItemList.size() > 0) {
                for (SaleOrderItem saleOrderItem : saleOrderItemList) {
                    ItemInfo itemInfo = new ItemInfo();
                    itemInfo.setImgUrl("");  //* 图片地址还要取
                    itemInfo.setItemId(saleOrderItem.getItemId());
                    itemInfo.setQuantity(saleOrderItem.getQuantity());
                    itemInfo.setItemTitle(saleOrderItem.getItemTitle());
                    itemInfo.setUnitPrice(saleOrderItem.getUnitPrice().doubleValue());
                    itemInfoList.add(itemInfo);
                }
            }
            saleOrderInfo.setItems(itemInfoList);

            saleOrderInfoList.add(saleOrderInfo);
        }

        return saleOrderInfoList;
    }

    @Override
    /**
     * 子订单详情
     */
    public SaleOrderInfo subDetail(@ApiParameter(required = true, name = "sale_no", desc = "订单号") String sale_no) throws ServiceException {

        if (sale_no == null || sale_no.isEmpty()) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }

        SaleOrderInfo saleOrderInfo = new SaleOrderInfo();

        //查询订单信息
        SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
        saleOrderCriteria.createCriteria().andSaleNoEqualTo(sale_no);
        List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);
        SaleOrder saleOrder = saleOrderList.size() > 0 ? saleOrderList.get(0) : null;

        if (saleOrder == null) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }
        saleOrderInfo.setOrderTime(saleOrder.getOrderTime().getTime());
        saleOrderInfo.setSaleNo(saleOrder.getSaleNo());
        saleOrderInfo.setShipDate(saleOrder.getShipDate().getTime());
        saleOrderInfo.setStatusValue("");
        saleOrderInfo.setPayStatus(saleOrder.getPayStatus());
        saleOrderInfo.setPayType(saleOrder.getPayType());

        //查询地址信息
        AddressInfo addressInfo = new AddressInfo();
        SaleOrderShipCriteria saleOrderShipCriteria = new SaleOrderShipCriteria();
        saleOrderShipCriteria.createCriteria().andSoNoEqualTo(sale_no);
        List<SaleOrderShip> saleOrderShipList = saleOrderShipLogic.list(saleOrderShipCriteria);
        SaleOrderShip saleOrderShip = saleOrderShipList.size() > 0 ? saleOrderShipList.get(0) : null;
        if (saleOrderShip != null) {
            addressInfo.setCity(saleOrderShip.getCity());
            addressInfo.setCityZone(saleOrderShip.getCityZone());
            addressInfo.setConsignee(saleOrderShip.getConsignee());
            addressInfo.setAddressDetail(saleOrderShip.getDetail());
            addressInfo.setMobile(saleOrderShip.getMobile());
            addressInfo.setProvince(saleOrderShip.getPrivince());
        }
        saleOrderInfo.setAddress(addressInfo);

        //查询商品信息
        SaleOrderItemCriteria saleOrderItemCriteria = new SaleOrderItemCriteria();
        saleOrderItemCriteria.createCriteria().andSoNoEqualTo(sale_no);
        List<SaleOrderItem> saleOrderItemList = saleOrderItemLogic.list(saleOrderItemCriteria);

        List<ItemInfo> itemInfoList = new ArrayList<ItemInfo>();
        if (saleOrderItemList.size() > 0) {
            for (SaleOrderItem saleOrderItem : saleOrderItemList) {
                ItemInfo itemInfo = new ItemInfo();
                itemInfo.setImgUrl("");  //* 图片地址还要取
                itemInfo.setItemId(saleOrderItem.getItemId());
                itemInfo.setQuantity(saleOrderItem.getQuantity());
                itemInfo.setItemTitle(saleOrderItem.getItemTitle());
                itemInfo.setUnitPrice(saleOrderItem.getUnitPrice().doubleValue());
                itemInfoList.add(itemInfo);
            }
        }
        saleOrderInfo.setItems(itemInfoList);
        return saleOrderInfo;
    }

    /**
     * 修改订单状态
     *
     * @param sale_no
     * @return
     * @throws ServiceException
     */
    @Override
    public OrderStatusInfo modifyOrderStatus(@ApiParameter(required = true, name = "sale_no", desc = "订单号") String sale_no,
                                             @ApiParameter(required = true, name = "status", desc = "订单状态") int status) throws ServiceException {

        if (sale_no == null || sale_no.isEmpty()) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }

        OrderStatusInfo orderStatusInfo = new OrderStatusInfo();

        //查询订单
        SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
        saleOrderCriteria.createCriteria().andSaleNoEqualTo(sale_no);
        List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);
        SaleOrder saleOrder = saleOrderList.size() > 0 ? saleOrderList.get(0) : null;

        if (saleOrder == null) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }

        //修改状态
        SaleOrder saleOrder_update = new SaleOrder();
        saleOrder_update.setId(saleOrder.getId());
        saleOrder_update.setStatus(status); //*状态后面要修改
        saleOrder_update.setVersion(saleOrder.getVersion());
        saleOrderLogic.updateSelective(saleOrder_update);

        //返回结果
        orderStatusInfo.setSaleNo(saleOrder_update.getSaleNo());
        orderStatusInfo.setStatus(saleOrder_update.getStatus());
        return orderStatusInfo;
    }

    public AddressInfo modifyOrderAddress(@ApiParameter(required = true, name = "address_id", desc = "地址ID") int address_id,
                                          @ApiParameter(required = true, name = "sale_no", desc = "订单号") String sale_no) throws ServiceException {

        //判断参数
        if (sale_no == null || sale_no.isEmpty()) {
            throw new ServiceException(OrderErrorCodes.getErrorCodes_ORDER_INPUT_ERROR);
        }

        SaleOrderShipCriteria saleOrderShipCriteria = new SaleOrderShipCriteria();
        saleOrderShipCriteria.createCriteria().andSoNoEqualTo(sale_no);
        List<SaleOrderShip> saleOrderShipList = saleOrderShipLogic.list(saleOrderShipCriteria);
        SaleOrderShip saleOrderShip = saleOrderShipList.size() > 0 ? saleOrderShipList.get(0) : null;
        if (saleOrderShip == null) {
            throw new ServiceException(OrderErrorCodes.getErrorCodes_ADDRESS_NOT_FOUND);
        }

        //会员服务，根据地址ID，查询地址信息
        //....TODO

        if (saleOrderShip != null) {
            saleOrderShip.setCity("1");
            saleOrderShip.setCityZone("1");
            saleOrderShip.setConsignee("1");
            saleOrderShip.setDetail("1");
            saleOrderShip.setMobile("1");
            saleOrderShip.setPrivince("1");
        }

        saleOrderShipLogic.updateSelective(saleOrderShip);

        AddressInfo addressInfo = new AddressInfo();
        addressInfo.setAddressId(address_id);
        addressInfo.setSaleNo(sale_no);
        return addressInfo;
    }

    @Override
    public OrderCommResponse findNonePayOrderByCustomerIdAndItemId(@ApiParameter(required = true, name = "customerId", desc = "用户ID") long customerId, @ApiParameter(required = true, name = "itemId", desc = "商品号") String itemId) throws ServiceException {
        OrderCommResponse response = new OrderCommResponse();
        HashMap paraMap = new HashMap();
        paraMap.put("itemId", itemId);
        paraMap.put("customerId", customerId + "");
        List<HashMap> rs = saleOrderItemLogic.selectNonePayOrderByCustomerIdAndItemId(paraMap);
        int unpayNum = 0;
        if(rs!=null && rs.size()>0){
            for (HashMap r : rs) {
                if(StringUtils.isNotBlank(r.get("quantity").toString())){
                    unpayNum += Integer.parseInt(r.get("quantity").toString());
                }
            }
        }
        response.setStatus("success");
        response.setResult(unpayNum+"");
        return response;
    }

    @Override
    public ResponseMessage batchConfirmSub(@ApiParameter(required = true, name = "shipping_date", desc = "子订单号") long shipping_date, @ApiParameter(required = true, name = "modify_by", desc = "修改人") String modify_by) throws ServiceException {
        ResponseMessage responseMessage = order.confirmSubOrders(shipping_date, modify_by);
        return responseMessage;
    }

    @Override
    public ResponseMessage modifySubItem(@ApiParameter(required = true, name = "shipping_date", desc = "配送日期") long shipping_date, @ApiParameter(required = true, name = "modify_by", desc = "修改人") String modify_by) throws ServiceException {
        return null;
    }

    @Override
    public ResponseMessage batchCreateSub(@ApiParameter(required = true, name = "shipping_date", desc = "配送日期") long shipping_date, @ApiParameter(required = true, name = "modify_by", desc = "修改人") String modify_by) throws ServiceException {
        Date shipping = new Date(shipping_date);
        return order.CreateSubOrders(shipping);
    }

    @Override
    public ResponseMessage suspendOrder(@ApiParameter(required = true, name = "no", desc = "主订单号") String no, @ApiParameter(required = true, name = "modify_by", desc = "修改人") String modify_by) throws ServiceException {
        ResponseMessage responseMessage = order.suspendOrder(no, modify_by);
        return responseMessage;
    }

    @Override
    public OrderStatusInfo confirmSub(@ApiParameter(required = true, name = "sale_no", desc = "订单号") String sale_no) throws ServiceException {

        //购物车
        //CartGetInfo cartGetInfo = cartService.cartGet();


        if (sale_no == null || sale_no.isEmpty()) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }

        OrderStatusInfo orderStatusInfo = new OrderStatusInfo();

        //查询订单
        SaleOrderCriteria saleOrderCriteria = new SaleOrderCriteria();
        saleOrderCriteria.createCriteria().andSaleNoEqualTo(sale_no);
        List<SaleOrder> saleOrderList = saleOrderLogic.list(saleOrderCriteria);
        SaleOrder saleOrder = saleOrderList.size() > 0 ? saleOrderList.get(0) : null;

        if (saleOrder == null) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }

        //判断状态
        if (saleOrder.getStatus() != 3) //* 状态后面要修改
        {
            throw new ServiceException(OrderErrorCodes.getErrorCodes_ORDER_STATUS_ERROR);
        }

        //修改状态
        SaleOrder saleOrder_update = new SaleOrder();
        saleOrder_update.setId(saleOrder.getId());
        saleOrder_update.setStatus(4); //*状态后面要修改
        saleOrder_update.setVersion(saleOrder.getVersion());
        saleOrderLogic.updateSelective(saleOrder_update);

        //返回结果
        orderStatusInfo.setSaleNo(saleOrder_update.getSaleNo());
        orderStatusInfo.setStatus(saleOrder_update.getStatus());
        return orderStatusInfo;
    }
    //endregion--------------------------------------------上面是暂时不用的接口--------------------------------------------------------------------

    //region--------------------------------------------下面是共通的方法--------------------------------------------------------------------
    private double formatFloat(double x) {
        return new Double(new DecimalFormat("###0.00").format(x));
    }

    /**
     * cps
     * @param emar_source
     * @param emar_channel
     * @param emar_cid
     * @param emar_wi
     * @param SaleNo
     * @throws ServiceException
     */
    private void  cps(String emar_source,String emar_channel,String emar_cid,String emar_wi,String SaleNo)throws ServiceException
    {
        try {
            if (emar_source != null && !emar_source.isEmpty() && emar_channel != null & !emar_channel.isEmpty() && emar_cid != null && !emar_cid.isEmpty() && emar_wi != null && !emar_wi.isEmpty()) {

                YqfTraceDTO traceDTO = new YqfTraceDTO();
                traceDTO.setChannel(emar_channel);
                traceDTO.setCid(emar_cid);
                traceDTO.setSource(emar_source);
                traceDTO.setWi(emar_wi);

                CpsTrace cpsTrace = new CpsTrace();
                cpsTrace.setSoNo(SaleNo);
                cpsTrace.setCreatedBy("system");
                cpsTrace.setModifiedTime(Calendar.getInstance().getTime());
                cpsTrace.setCreatedBy("system");
                cpsTrace.setCreatedTime(Calendar.getInstance().getTime());
                cpsTrace.setJsonValue(JsonUtils.obj2Json(traceDTO));
                cpsTrace.setCpsProvider(traceDTO.getSource());

                cpsTraceLogic.insert(cpsTrace);
            }
        } catch (Exception e) {
            logger.error("save cps trace exception . sale no = " + SaleNo);
            logger.error(e.toString());
            throw new ServiceException(OrderErrorCodes.errorCodes_CARTPRODUCT_NOT_FOUND, e.toString());
        }
    }


    /**
     * 发送预警邮件
     * @param subject
     * @param content
     */
    private void sendYJEmail(String subject,String content)
    {
        try{
            memberService.sendOrderWarningEmail(subject, content);
        }catch (Exception ex)
        {
            logger.error("【会员服务|发送订单预警邮件】 报错" );
            logger.error("信息： subject:"+subject+" content:"+content);
            logger.error(ex);
        }
    }
    /**
     *   满减可用优惠券排序
     *   默认显示可用优惠券中优惠力度最大的一个
     *   若优惠力度相同的券有多张时，显示一张过期时间最近的
     *   若优惠力度、过期时间相同、显示领取时间最早的一张
     *   优惠力度、过期时间相同、显示领取时间相同，则显示优惠券ID最小的一个
     */

    private void sortCoupon(List<ProInfo> trueCouponInfoReduce){
        Collections.sort(trueCouponInfoReduce, new Comparator<ProInfo>() {
            public int compare(ProInfo arg0, ProInfo arg1) {
                //优惠力度：满100-99 优惠力度等于99/100
                double hits0 = arg0.getRules().getPreferential()/arg0.getRules().getLimit();
                double hits1 = arg1.getRules().getPreferential()/arg1.getRules().getLimit();
                long endDate0 = arg0.getEnd();
                long endDate1 = arg1.getEnd();
                long startDate0 = arg0.getCreatetime();
                long startDate1 = arg1.getCreatetime();
                long id0 = arg0.getId();
                long id1 = arg1.getId();
                if (hits1 > hits0) {//比较优惠券优惠金额力度 降序
                    return 1;
                } else if (hits1 == hits0) {
                    if(endDate0>endDate1){//比较优惠券作废日期 升序
                        return 1;
                    }else if(endDate0==endDate1){
                        if(startDate0>startDate1){//比较优惠券领取日期 升序
                            return 1;
                        }else if (startDate0==startDate1){
                            if(id0>id1){ //比较优惠券ID升序
                                return 1;
                            }else if(id0==id1){
                                return 0 ;
                            }else{
                                return -1;
                            }
                        }else{
                            return -1;
                        }
                    }else{
                        return -1;
                    }
                } else {
                    return -1;
                }
            }
        });
    }

    /**
     * 包邮可用优惠券排序
     * 默认显示可用的包邮券满足金额最大的券
     * 若包邮券满足金额最大券一样，则显示一张过期时间最近的
     * 若包邮券满足金额最大和显示一张过期时间一样的，则显示领取时间最早的一张
     * 若包邮券满足金额最大、显示一张过期时间、领取时间一样，则显示优惠券ID最小的一个
     * 无可用券，操作同原先老版本一样
     * @param trueCouponInfoPost
     */
    private void sortCouponPost(List<ProInfo> trueCouponInfoPost){
        Collections.sort(trueCouponInfoPost, new Comparator<ProInfo>() {
            public int compare(ProInfo arg0, ProInfo arg1) {
                double hits0 = arg0.getRules().getPreferential();
                double hits1 = arg1.getRules().getPreferential();
                long endDate0 = arg0.getEnd();
                long endDate1 = arg1.getEnd();
                long startDate0 = arg0.getCreatetime();
                long startDate1 = arg1.getCreatetime();
                long id0 = arg0.getId();
                long id1 = arg1.getId();
                if (hits1 > hits0) {//比较优惠券优惠金额 降序
                    return 1;
                } else if (hits1 == hits0) {
                    if(endDate0>endDate1){//比较优惠券作废日期 升序
                        return 1;
                    }else if(endDate0==endDate1){
                        if(startDate0>startDate1){//比较优惠券领取日期 升序
                            return 1;
                        }else if (startDate0==startDate1){
                            if(id0>id1){ //比较优惠券ID升序
                                return 1;
                            }else if(id0==id1){
                                return 0 ;
                            }else{
                                return -1;
                            }
                        }else{
                            return -1;
                        }
                    }else{
                        return -1;
                    }
                } else {
                    return -1;
                }
            }
        });
    }
    //endregion--------------------------------------------上面是共通的方法--------------------------------------------------------------------

    /**
     * 部分支付订单取消（退款：仅余额的部分支付）
     * @param sale_no 订单编号
     * @throws ServiceException
     */
    public RefundResultInfo partialPayCancel(String sale_no) throws ServiceException{
        RefundResultInfo resultInfo = new RefundResultInfo();
        resultInfo.setStatus(false);
        resultInfo.setMsg("none");

        SaleOrder order = this.getOrderBySo(sale_no);

        if(null != order)
        {
            if(!(order.getStatus() == SaleOrderStatus.Created.value() && order.getPayStatus() == SaleOrderPayStatus.PartialPay.value())) {
                resultInfo.setMsg("当前订单状态不允许取消");
                logger.info(String.format("订单：%s 取消失败，订单状态非已创建，部分支付",sale_no));
                return resultInfo;
            }
            // region 检索支付记录 & 组织退款记录
            SaleOrderPayCriteria criteria = new SaleOrderPayCriteria();
            criteria.createCriteria().andSoNoEqualTo(sale_no);
            List<SaleOrderPay> payList = saleOrderPayLogic.list(criteria);
            List<SaleOrderRefund> refundList = new ArrayList<>(payList.size());

            double paySum =  0;
            for(SaleOrderPay item : payList){
                if(!item.getPayChannel().equalsIgnoreCase("Balance") && (item.getStatus() == PayStatus.Success.value())){
                    resultInfo.setMsg("部分支付订单取消仅支持余额支付！");
                    return resultInfo;
                }

                if(item.getStatus() == PayStatus.Success.value()){
                    paySum += item.getAmount().doubleValue();

                    SaleOrderRefund refundObject = new SaleOrderRefund();
                    refundObject.setModifiedTime(new Date());
                    refundObject.setCreatedTime(new Date());
                    refundObject.setModifiedBy("system");
                    refundObject.setCreatedBy("system");
                    refundObject.setAmount(order.getPaidAmount());
                    refundObject.setPayId(item.getId());
                    refundObject.setStatus(RefundStatus.Succeed.value());
                    refundObject.setPayChannel("Balance");
                    refundObject.setSoNo(sale_no);
                    refundList.add(refundObject);
                }
            }
            if(paySum != order.getPaidAmount().doubleValue()){
                resultInfo.setMsg("支付合计与订单显示不符，取消并退款失败");
                return  resultInfo;
            }
            //endregion 检索支付记录

            //提交退还U鲜卡请求到OM数据库操作
            com.ulife.member.api.response.BalanceRefundResultInfo rtnObject = memberService.partialPayCancel(sale_no,
                    order.getCustomerId(),
                    order.getPaidAmount().doubleValue(),
                    order.getSaleChannel());
            if(rtnObject.getStatus()) {
                //region 插入退款记录
                for (SaleOrderRefund item : refundList) {
                    saleOrderRefundLogic.insert(item);
                }
                //endregion

                //region 更新订单状态，已注释，在cancel方法中有此段代码
//                order.setStatus(SaleOrderStatus.Cancel.value());
//                order.setPayStatus(SaleOrderPayStatus.WaitPay.value());
//                order.setModifiedTime(new Date());
//                order.setModifiedBy("system");
//                order.setVersion(order.getVersion() + 1);
//                saleOrderLogic.update(order);
                //endregion
            }else {
                resultInfo.setMsg("U鲜卡更新余额未完成，订单取消及退款失败");
                logger.warn("U鲜卡更新余额未完成，订单取消及退款失败");
                return resultInfo;
            }
            resultInfo.setStatus(true);
            resultInfo.setMsg("success");
            return  resultInfo;
        }else{
            resultInfo.setMsg("订单" + sale_no + "不存在");
        }
        return  resultInfo;
    }
    /**
     *  查询部分支付的订单是否可以取消并退款
     * @param sale_no 订单编号
     * @return "CannotPayCancel":不可取消并退款；“CanPayCancel”：可以取消并退款
     */
    private String getCanPartialPayCancel(String sale_no){
        String actionCode = "CannotPayCancel";
        SaleOrderPayCriteria criteria = new SaleOrderPayCriteria();
        criteria.createCriteria().andSoNoEqualTo(sale_no);
        List<SaleOrderPay> payList = saleOrderPayLogic.list(criteria);
        double paidAmount = 0;
        for (SaleOrderPay payItem :payList) {
            if (payItem.getPayChannel().equalsIgnoreCase("Balance")){
                if(payItem.getStatus().intValue() == PayStatus.Success.value()){
                    paidAmount +=(payItem.getAmount().doubleValue());
                }
            }else{
                //存在其他的支付方式，并且已支付成功时，直接返回“CannotCancel”
                if(payItem.getStatus().intValue() == PayStatus.Success.value()){return actionCode;}
            }
        }
        if(paidAmount > 0){
            actionCode = "CanPayCancel";
        }
        return actionCode;
    }

    //region 内部管理使用（order.cms.*）
    /**
     * 拉取订单列表（内部管理使用）
     * @param start_date 创建订单的开始时间
     * @param end_date 创建订单的结束时间
     * @param sale_no 主单号
     * @param ship_no 发货单号
     * @param consignee_name 收货人名称
     * @param consignee_mobile_no 收货人手机号
     * @param login_name 客户账号（登陆名）
     * @return
     */
    @Override
    public SaleOrderListInfo getOrderList(long start_date,
                                          long end_date,
                                          String sale_no,
                                          String ship_no,
                                          String consignee_name,
                                          String consignee_mobile_no,
                                          String login_name,
                                          int page,
                                          int rows)throws ServiceException {
        SaleOrderListInfo result = new SaleOrderListInfo();


    /*    long interval_Millis = order_end_date.getTime() - order_start_date.getTime();
        long interval_Days = interval_Millis/(1000 * 60 * 60 * 24);

        if(interval_Days > 60) {
            throw new ServiceException(OrderErrorCodes.getErrorCodes_ORDER_LIST_RANGE_ERROR, "查询时间间隔大于两个月");
        }*/
        CustomerDto customer = null;
        if(!Strings.isNullOrEmpty(login_name)){
            customer = memberService.getCustomerByLoginName(login_name);
            if(null == customer || customer.customerId <= 0){
                //账号不存在时，返回空
                return null;
            }
        }
        if (page == 0) page = 1;
        // 计算总记录数量
        String totCountCondition = this.getQueryConditionOfOrder(start_date,end_date,
                sale_no,
                ship_no,
                consignee_name,
                consignee_mobile_no,customer== null ? 0 : customer.customerId,0,0);

        String whereCondition = this.getQueryConditionOfOrder(start_date,end_date,
                sale_no,
                ship_no,
                consignee_name,
                consignee_mobile_no,customer== null ? 0 : customer.customerId,page,rows);

        int totalCount = saleOrderLogic.orderViewCountExtendSql(new SQLAdapter(totCountCondition)); //计算数据总记录数量
        List<SaleOrder> orderList = saleOrderLogic.orderViewExtendSql(new SQLAdapter(whereCondition)); //检索分页后的数据
        List<SaleOrderInfo> orderInfoList = this.orderInfoListMapping(orderList);

        result.setCount(totalCount);
        result.setOrders(orderInfoList);
        return result;
    }

    /**
     *  组织订单的查询条件 （内部管理使用）
     * @param start_date 创建订单的开始时间
     * @param end_date 创建订单的结束时间
     * @param pageIndex 分页索引
     * @return
     */
    private String getQueryConditionOfOrder(long start_date,long end_date,
                                            String sale_no,
                                            String ship_no,
                                            String consignee_name,
                                            String consignee_mobile_no,
                                            long customer_id,int pageIndex,int rows){
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        String sale_no_Condition = Strings.isNullOrEmpty(sale_no) ? "" : String.format(" AND sale_order.sale_no = '%s'", sale_no.trim());
        String ship_no_Condition = Strings.isNullOrEmpty(ship_no) ? "" : String.format(" AND sale_order.sale_no = '%s'", ship_no.trim());
        String consignee_name_Condition = Strings.isNullOrEmpty(consignee_name) ? "" : String.format(" AND sale_order_ship.consignee = '%s'",consignee_name.trim());
        String consignee_mobile_no_Condition = Strings.isNullOrEmpty(consignee_mobile_no) ? "" : String.format(" AND sale_order_ship.mobile = '%s'",consignee_mobile_no.trim());
        String login_name_Condition ="";

        if(customer_id!=0){
            login_name_Condition=String.format(" AND sale_order.customer_id = %d",customer_id);
        }

        StringBuilder temp = new StringBuilder();
        temp.append("  1=1 ");
        if(start_date!=0){
            temp.append(String.format(" AND sale_order.created_time >= '%s'",dateFormat.format(new Date(start_date))));
        }
        if(end_date!=0){
            temp.append(String.format(" AND sale_order.created_time <= '%s'",dateFormat.format(new Date(end_date))));
        }

        temp.append(sale_no_Condition);
        temp.append(ship_no_Condition);
        temp.append(consignee_name_Condition);
        temp.append(consignee_mobile_no_Condition);
        temp.append(login_name_Condition);
        temp.append(" AND sale_order.order_type = 'main'");
        if(pageIndex > 0) {
            temp.append(" ORDER BY sale_order.order_time DESC");
            temp.append(String.format(" limit %d,%d", (pageIndex - 1) * rows,rows));
        }

        return  temp.toString();
    }

    /**
     *  检索订单明细（内部管理使用）
     * @param sale_no 订单编号
     * @return 订单商品明细列表
     */
    public List<ItemInfo> getOrderItems(String sale_no){
        return this.getOrderItemInfoList(sale_no);
    }

    /***
     *  检索订单的支付记录
     * @param sale_no 订单编号
     * @return 订单支付记录
     */
    public List<SaleOrderPayInfo> getOrderPayItems(String sale_no){
        return this.getOrderPayList(sale_no);
    }

    /***
     *  检索订单的支付记录
     * @param sale_no 订单编号
     * @return 订单支付记录
     */
    private List<SaleOrderPayInfo> getOrderPayList(String sale_no){
        List<SaleOrderPayInfo> payInfoList = null;
        SaleOrderPayCriteria criteria = new SaleOrderPayCriteria();
        criteria.createCriteria().andSoNoEqualTo(sale_no);
        List<SaleOrderPay> payList = saleOrderPayLogic.list(criteria);

        if(null != payList && payList.size() > 0){
            payInfoList = new ArrayList<>(payList.size());
            for (int i=0;i<payList.size();i++){
                SaleOrderPayInfo payInfo = new SaleOrderPayInfo();
                payInfo.setAmount(payList.get(i).getAmount().doubleValue());
                payInfo.setBankSerialNo(payList.get(i).getBankSerialNo());
                payInfo.setCreatedBy(payList.get(i).getCreatedBy());
                payInfo.setCreatedTime(payList.get(i).getCreatedTime().getTime());
                payInfo.setId(payList.get(i).getId());
                payInfo.setPayChannel(payList.get(i).getPayChannel());
                payInfo.setTxSerialNumber(payList.get(i).getTxSerialNumber());
                payInfo.setStatus(payList.get(i).getStatus());
                payInfoList.add(payInfo);
            }
        }
        return  payInfoList;
    }

    /**
     *  订单详情
     * @param saleNo 订单编号
     * @return
     * @throws ServiceException
     */
    @Override
    public OrderInfoResponse getOrderInfo(@ApiParameter(required = true, name = "saleNo", desc = "订单编号") String saleNo) throws ServiceException {

        if (saleNo == null || saleNo.isEmpty()) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }
        SaleOrderInfo orderInfo = getOrderInfoBySo(saleNo);
        //查询订单信息
        if (orderInfo == null) {
            throw new ServiceException(OrderErrorCodes.errorCodes_ORDER_NOT_FOUND);
        }
        OrderInfoResponse infoResponse= new OrderInfoResponse();
        //查询订单信息
        infoResponse=getOrderInfoBySaleNo(saleNo);

        //查询地址信息
        AddressInfo addressInfo = null;
        addressInfo = getAddressInfoBySo(saleNo);
        infoResponse.setAddress(addressInfo);

        //订单中所有商品
        List<ItemInfo> itemInfoList = getOrderItemShipInfo(saleNo);
        infoResponse.setItems(itemInfoList);
        double totalPrice = 0;
        for (ItemInfo item : itemInfoList) {
            totalPrice+=item.subTotal;
        }
        totalPrice = new Double(new DecimalFormat("####0.00").format(totalPrice));
        infoResponse.setItemsTotalPrice(totalPrice);

        //查询订单备注信息
        List<SoComments> soCommentses=null;
        SoCommentsCriteria soCommentsCriteria=new SoCommentsCriteria();
        SoCommentsCriteria.Criteria soComments_criteria=soCommentsCriteria.createCriteria();
        soComments_criteria.andSoNoEqualTo(orderInfo.getSaleNo());
        soCommentses=soCommentsLogic.list(soCommentsCriteria);
        List<SoCommentsDTO> list = new ArrayList<SoCommentsDTO>();
        if (soCommentses.size()>0) {
            for (SoComments comments : soCommentses) {
                SoCommentsDTO   dto = new SoCommentsDTO();
                dto.setType(comments.getType());
                dto.setSoNo(comments.getSoNo());
                dto.setOrderStatus(comments.getOrderStatus());
                dto.setPayStatus(comments.getPayStatus());
                dto.setRemark(comments.getRemark());
                dto.setCreateTime(comments.getCreateTime().getTime());
                list.add(dto);
            }
        }
        infoResponse.setComments(list);

        //订单支付信息
        List<SaleOrderPayInfo> salePayInfoList = this.getOrderPayList(saleNo);
        infoResponse.setPayInfoList(salePayInfoList);

        //订单退款信息
        List<SaleOrderRefundInfo> refundList = this.getSaleRefundInfos(saleNo);
        infoResponse.setRefundList(refundList);

        return infoResponse;
    }

    /**
     * 根据订单号获取订单返回信息
     *
     * @return
     */
    private OrderInfoResponse getOrderInfoBySaleNo(String sale_no) {
        OrderInfoResponse orderInfo = null;
        SaleOrder saleOrder = getOrderBySo(sale_no);
        if (saleOrder == null) {
            return orderInfo;
        }
        orderInfo = new OrderInfoResponse();
        orderInfo.setCustomerId(saleOrder.getCustomerId());
        orderInfo.setOrderTime(saleOrder.getOrderTime().getTime());
        orderInfo.setSaleNo(saleOrder.getSaleNo());
        orderInfo.setShipDate(saleOrder.getShipDate().getTime());
        orderInfo.setOrderCategory(saleOrder.getOrderCategory());
        orderInfo.setGroupId(saleOrder.getGroupId());
        orderInfo.setPayStatus(saleOrder.getPayStatus());
        orderInfo.setPayType(saleOrder.getPayType());
        orderInfo.setSubAmount(saleOrder.getSubAmount().doubleValue());
        orderInfo.setPromotionDiscount(saleOrder.getPromotionDiscount().doubleValue());
        orderInfo.setProductCouponDiscount(saleOrder.getProductCouponDiscount().doubleValue());
        orderInfo.setShipFee(saleOrder.getShipFee().doubleValue());
        orderInfo.setShipFeeDiscount(saleOrder.getShipFeeDiscount().doubleValue());
        orderInfo.setShipFeeCouponDiscount(saleOrder.getShipFeeCouponDiscount().doubleValue());
        orderInfo.setTotalAmount(saleOrder.getTotalAmount().doubleValue());
        orderInfo.setPaidAmount(saleOrder.getPaidAmount().doubleValue());
        orderInfo.setCreatedBy(saleOrder.getCreatedBy());
        orderInfo.setStatus(saleOrder.getStatus());
        orderInfo.setStatusValue(OrderStatusMapping(saleOrder.getStatus(), saleOrder.getPayType(), saleOrder.getOrderCategory(), saleOrder.getPayStatus()));
        orderInfo.setTerminal(saleOrder.getTerminal());
        orderInfo.setSaleChannel(saleOrder.getSaleChannel());
        return orderInfo;
    }

    /**
     *  查询订单退款记录
     * @param order_no 订单编号
     * @return 订单退款列表
     */
    public List<SaleOrderRefundInfo> getSaleRefundInfos(String order_no){
        SaleOrderRefundCriteria criteria = new SaleOrderRefundCriteria();
        criteria.createCriteria().andSoNoEqualTo(order_no);

        java.util.List<SaleOrderRefund> list = this.saleOrderRefundLogic.list(criteria);

        List<SaleOrderRefundInfo> result = this.saleOrderRefundInfoMapping(list);
        return  result;
    }

    /**
     *  映射封装订单退款记录
     * @param refundItems 原始订单退款记录
     * @return
     */
    private  List<SaleOrderRefundInfo> saleOrderRefundInfoMapping(java.util.List<SaleOrderRefund> refundItems){
        List<SaleOrderRefundInfo> result = new ArrayList<SaleOrderRefundInfo>();
        for (SaleOrderRefund item : refundItems){
            SaleOrderRefundInfo info = new SaleOrderRefundInfo();
            info.setAmount(item.getAmount().doubleValue());
            info.setModifiedBy(item.getModifiedBy());
            info.setModifiedBy(item.getModifiedBy());
            info.setCreatedTime(item.getCreatedTime().getTime());
            info.setModifiedTime(item.getModifiedTime().getTime());
            info.setPayChannel(item.getPayChannel());
            info.setPayId(item.getPayId());
            info.setSoNo(item.getSoNo());
            info.setRefund_Status(item.getStatus());
            result.add(info);
        }
        return result;
    }

    /**
     *  查询订单商品明细发货信息
     * @param sale_no 订单编号
     * @return
     */
    private  List<ItemInfo> getOrderItemShipInfo(String sale_no){
        List<ItemInfo> result = new ArrayList<>();
        List<SaleOrderItemShipment>  list;
        list = saleOrderItemLogic.getSaleOrderItemShip(sale_no);
        if(null != list && list.size() > 0){
            for (SaleOrderItemShipment item : list){
                ItemInfo itemInfo = new ItemInfo();
                itemInfo.setImgUrl(item.getImgUrl());  //* 图片地址还要取
                itemInfo.setItemId(item.getItemId());
                itemInfo.setQuantity(item.getQuantity());
                itemInfo.setItemTitle(item.getItemTitle());
                itemInfo.setWeight(item.getWeight().doubleValue());
                itemInfo.setUnitPrice(item.getUnitPrice().doubleValue());
                itemInfo.setItemForm(item.getItemForm());
                itemInfo.setPromoId((item.getPromoId() == null) ? 0 : item.getPromoId());
                itemInfo.setPrivateWesen((item.getPrivateWesen() == null) ? "" : item.getPrivateWesen());
                itemInfo.setPublicWesen((item.getPublicWesen() == null) ? "" : item.getPublicWesen()); //oto
                itemInfo.setSubTotal((item.getUnitPrice().doubleValue() * item.getQuantity()));
                itemInfo.setSkuCode(item.getSkuCode());
                itemInfo.setSkuId(item.getSkuId());
                itemInfo.setShipOrderNo(item.getShipOrderNo());
                result.add(itemInfo);
            }
        }
        return result;
    }
    //endregion 内部管理使用

    //region 创建订单前检查商品库存

    /**
     * 下单：检查商品库存是否满足
     * @param saleOrderItemList 订单商品明细
     * @param orderStatus 下单返回结果对象
     * @return 订单商品是否全库存满足
     * @throws ServiceException
     */
    private boolean checkStock(List<SaleOrderItem> saleOrderItemList,OrderStatusInfo orderStatus) throws ServiceException{
        boolean isFullStock = false; //所有的商品数量都满足
        if(null == saleOrderItemList || saleOrderItemList.size() == 0){
            throw new ServiceException(OrderErrorCodes.errorCodes_CARTPRODUCT_NOT_FOUND,"下单前库存检查失败：商品明细为空");
        }else{
            if(orderStatus == null) orderStatus = new OrderStatusInfo();

            for (SaleOrderItem item : saleOrderItemList){
                ProductStockResponse stockResponse = stockService.getStock(item.getItemId(),1);
                if(null == stockResponse)
                    throw new ServiceException(OrderErrorCodes.errorCodes_GENERATER_ORDER_STOCK_ERROR,"下单前库存检查失败：库存检操作异常");
                else {
                    if(stockResponse.getStock() >= item.getQuantity()){
                        continue;
                    }else{
                        //小于订单数量...
                        orderStatus.addOutStockItem(item.getItemId(),item.getSkuName(),item.getQuantity(),stockResponse.getStock());
                    }
                }
            }
        }
        if(orderStatus.outStockItemList == null || orderStatus.outStockItemList.size() == 0)
            isFullStock =  true;
        return isFullStock;
    }
    //endregion
}
